Skip to content

Commit 49eccae

Browse files
committed
shared/tinyusb: Add per-driver runtime USB class control.
This change allows USB class drivers (CDC, MSC, NCM) to be individually enabled/disabled at runtime without requiring TinyUSB submodule changes. Classes are always compiled in but only enabled drivers appear in USB descriptors. When runtime device mode is disabled, all compiled classes are auto-enabled for backward compatibility. When enabled, only CDC is enabled by default. Signed-off-by: Andrew Leech <[email protected]>
1 parent a27d521 commit 49eccae

File tree

5 files changed

+369
-11
lines changed

5 files changed

+369
-11
lines changed

extmod/machine_usb_device.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,58 @@ static mp_obj_t usb_device_config(size_t n_args, const mp_obj_t *pos_args, mp_ma
229229
}
230230
static MP_DEFINE_CONST_FUN_OBJ_KW(usb_device_config_obj, 1, usb_device_config);
231231

232+
// Per-class control methods
233+
static mp_obj_t usb_device_enable_cdc(size_t n_args, const mp_obj_t *args) {
234+
mp_obj_usb_device_t *self = MP_OBJ_TO_PTR(args[0]);
235+
236+
if (self->active) {
237+
mp_raise_OSError(MP_EINVAL);
238+
}
239+
240+
if (n_args == 1) {
241+
return mp_obj_new_bool(mp_usbd_class_state.cdc_enabled);
242+
} else {
243+
bool enable = mp_obj_is_true(args[1]);
244+
mp_usbd_enable_class_cdc(enable);
245+
return mp_const_none;
246+
}
247+
}
248+
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usb_device_enable_cdc_obj, 1, 2, usb_device_enable_cdc);
249+
250+
static mp_obj_t usb_device_enable_msc(size_t n_args, const mp_obj_t *args) {
251+
mp_obj_usb_device_t *self = MP_OBJ_TO_PTR(args[0]);
252+
253+
if (self->active) {
254+
mp_raise_OSError(MP_EINVAL);
255+
}
256+
257+
if (n_args == 1) {
258+
return mp_obj_new_bool(mp_usbd_class_state.msc_enabled);
259+
} else {
260+
bool enable = mp_obj_is_true(args[1]);
261+
mp_usbd_enable_class_msc(enable);
262+
return mp_const_none;
263+
}
264+
}
265+
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usb_device_enable_msc_obj, 1, 2, usb_device_enable_msc);
266+
267+
static mp_obj_t usb_device_enable_ncm(size_t n_args, const mp_obj_t *args) {
268+
mp_obj_usb_device_t *self = MP_OBJ_TO_PTR(args[0]);
269+
270+
if (self->active) {
271+
mp_raise_OSError(MP_EINVAL);
272+
}
273+
274+
if (n_args == 1) {
275+
return mp_obj_new_bool(mp_usbd_class_state.ncm_enabled);
276+
} else {
277+
bool enable = mp_obj_is_true(args[1]);
278+
mp_usbd_enable_class_ncm(enable);
279+
return mp_const_none;
280+
}
281+
}
282+
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usb_device_enable_ncm_obj, 1, 2, usb_device_enable_ncm);
283+
232284
static const MP_DEFINE_BYTES_OBJ(builtin_default_desc_dev_obj,
233285
&mp_usbd_builtin_desc_dev, sizeof(tusb_desc_device_t));
234286

@@ -278,6 +330,11 @@ static const mp_rom_map_elem_t usb_device_locals_dict_table[] = {
278330
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&usb_device_active_obj) },
279331
{ MP_ROM_QSTR(MP_QSTR_stall), MP_ROM_PTR(&usb_device_stall_obj) },
280332
{ MP_ROM_QSTR(MP_QSTR_remote_wakeup), MP_ROM_PTR(&usb_remote_wakeup_obj) },
333+
334+
// Per-class control methods
335+
{ MP_ROM_QSTR(MP_QSTR_enable_cdc), MP_ROM_PTR(&usb_device_enable_cdc_obj) },
336+
{ MP_ROM_QSTR(MP_QSTR_enable_msc), MP_ROM_PTR(&usb_device_enable_msc_obj) },
337+
{ MP_ROM_QSTR(MP_QSTR_enable_ncm), MP_ROM_PTR(&usb_device_enable_ncm_obj) },
281338

282339
// Built-in driver constants
283340
{ MP_ROM_QSTR(MP_QSTR_BUILTIN_NONE), MP_ROM_PTR(&mp_type_usb_device_builtin_none) },

shared/tinyusb/mp_usbd.h

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,35 @@ extern void mp_usbd_port_get_serial_number(char *buf);
8080
// length (2 * bytes_len + 1) (including NUL terminator).
8181
void mp_usbd_hex_str(char *out_str, const uint8_t *bytes, size_t bytes_len);
8282

83+
// Per-class runtime enable/disable state
84+
typedef struct {
85+
bool cdc_enabled;
86+
bool msc_enabled;
87+
bool ncm_enabled;
88+
} mp_usbd_class_state_t;
89+
90+
// Global class enable state
91+
extern mp_usbd_class_state_t mp_usbd_class_state;
92+
93+
// Functions to control USB classes via bitfield flags
94+
void mp_usbd_update_class_state(uint8_t flags);
95+
void mp_usbd_init_class_state(void);
96+
97+
// Initialise TinyUSB device.
98+
static inline void mp_usbd_init_tud(void) {
99+
// Initialize class state before TinyUSB init
100+
mp_usbd_init_class_state();
101+
102+
tusb_init();
103+
#if MICROPY_HW_USB_CDC
104+
tud_cdc_configure_fifo_t cfg = { .rx_persistent = 0, .tx_persistent = 1 };
105+
tud_cdc_configure_fifo(&cfg);
106+
#endif
107+
}
108+
109+
// Get dynamic descriptor length based on enabled classes
110+
size_t mp_usbd_get_descriptor_cfg_len(void);
111+
83112
// Length of built-in configuration descriptor
84113
#define MP_USBD_BUILTIN_DESC_CFG_LEN ( \
85114
(CFG_TUD_CDC ? (TUD_CDC_DESC_LEN) : 0) + \
@@ -102,6 +131,7 @@ const char *mp_usbd_runtime_string_cb(uint8_t index);
102131
// Maximum number of pending exceptions per single TinyUSB task execution
103132
#define MP_USBD_MAX_PEND_EXCS 2
104133

134+
// Full runtime USB device structure
105135
typedef struct {
106136
mp_obj_base_t base;
107137

@@ -136,6 +166,23 @@ typedef struct {
136166
mp_obj_t pend_excs[MP_USBD_MAX_PEND_EXCS];
137167
} mp_obj_usb_device_t;
138168

169+
#else // Static USBD drivers only
170+
171+
// Minimal USB device structure for static mode (builtin_driver control only)
172+
typedef struct {
173+
mp_obj_base_t base;
174+
mp_obj_t builtin_driver; // Points to one of mp_type_usb_device_builtin_nnn
175+
bool active; // Has the user set the USB device active?
176+
} mp_obj_usb_device_t;
177+
178+
static inline void mp_usbd_init(void) {
179+
// Without runtime USB support, this can be a thin wrapper wrapper around tusb_init()
180+
// which is called in the below helper function.
181+
mp_usbd_init_tud();
182+
}
183+
184+
#endif
185+
139186
// Built-in constant objects, possible values of builtin_driver
140187
//
141188
// (Currently not possible to change built-in drivers at runtime, just enable/disable.)
@@ -147,16 +194,6 @@ static inline bool mp_usb_device_builtin_enabled(const mp_obj_usb_device_t *usbd
147194
return usbd->builtin_driver != MP_OBJ_FROM_PTR(&mp_type_usb_device_builtin_none);
148195
}
149196

150-
#else // Static USBD drivers only
151-
152-
static inline void mp_usbd_init(void) {
153-
// Without runtime USB support, this can be a thin wrapper wrapper around tusb_init()
154-
// which is called in the below helper function.
155-
mp_usbd_init_tud();
156-
}
157-
158-
#endif
159-
160197
#endif // MICROPY_HW_ENABLE_USBDEV
161198

162199
#endif // MICROPY_INCLUDED_SHARED_TINYUSB_USBD_H

0 commit comments

Comments
 (0)