CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
UsbManager.cpp
Go to the documentation of this file.
2#include "cdc_log.h"
3#include "usb_badge/usb_hid.h"
4#include <string.h>
5
6static const char* TAG = "UsbManager";
7
8namespace cdc::core {
9
15 static UsbManager s_instance;
16 return s_instance;
17}
18
25 return true;
26}
27
33 state_ = ServiceState::STARTED;
34 return true;
35}
36
41 state_ = ServiceState::STOPPED;
42}
43
48uint8_t UsbManager::activeHidCount() const {
49 uint8_t count = 0;
50 for (const auto& entry : entries_) {
51 if (entry.active) count++;
52 }
53 return count;
54}
55
61bool UsbManager::canActivate(UsbHidInterface type) const {
62 (void)type;
63 return activeHidCount() < MAX_ACTIVE_HID;
64}
65
71uint8_t UsbManager::interfaceEndpoints(const UsbInterfaceSpec& def) {
72 if (def.cls == UsbInterfaceClass::Ccid) return 2;
73 return def.hasOut ? 2 : 1;
74}
75
80uint8_t UsbManager::endpointsInUse() const {
81 uint8_t n = CDC_ENDPOINTS;
82 for (const auto& entry : entries_) {
83 if (entry.active) n += interfaceEndpoints(entry.def);
84 }
85 if (mscActive_) n += MSC_ENDPOINTS;
86 return n;
87}
88
96bool UsbManager::registerInterface(UsbHidInterface type, const char* moduleName,
97 const UsbInterfaceSpec& def) {
98 const uint8_t idx = static_cast<uint8_t>(type);
99 if (idx >= (sizeof(entries_) / sizeof(entries_[0]))) return false;
100
101 auto& entry = entries_[idx];
102 if (entry.active) {
103 if (entry.owner && moduleName && strcmp(entry.owner, moduleName) == 0) {
104 return true;
105 }
106 LOG_W(TAG, "Interface %d already owned by %s", idx, entry.owner ? entry.owner : "?");
107 return false;
108 }
109
110 if (!canActivate(type)) {
111 LOG_W(TAG, "HID interface limit reached (max %d)", MAX_ACTIVE_HID);
112 return false;
113 }
114
115 if (endpointsInUse() + interfaceEndpoints(def) > MAX_ENDPOINTS) {
116 LOG_W(TAG, "USB endpoint budget exhausted (have %d/%d, +%d)",
117 endpointsInUse(), MAX_ENDPOINTS, interfaceEndpoints(def));
118 return false;
119 }
120
121 entry.active = true;
122 entry.owner = moduleName;
123 entry.def = def;
124 activeMask_ |= (1u << idx);
125 LOG_I(TAG, "Registered HID interface %d for %s", idx, moduleName ? moduleName : "?");
127 return true;
128}
129
135void UsbManager::unregisterInterface(UsbHidInterface type, const char* moduleName) {
136 const uint8_t idx = static_cast<uint8_t>(type);
137 if (idx >= (sizeof(entries_) / sizeof(entries_[0]))) return;
138
139 auto& entry = entries_[idx];
140 if (!entry.active) return;
141 if (entry.owner && moduleName && strcmp(entry.owner, moduleName) != 0) {
142 LOG_W(TAG, "Interface %d owned by %s, not %s", idx,
143 entry.owner ? entry.owner : "?", moduleName ? moduleName : "?");
144 return;
145 }
146
147 entry.active = false;
148 entry.owner = nullptr;
149 entry.def = {};
150 activeMask_ &= ~(1u << idx);
151 LOG_I(TAG, "Unregistered HID interface %d", idx);
153}
154
160 needsReplug_ = false;
161 UsbInterfaceSpec defs[3] = {};
162 size_t count = 0;
163
164 auto append_def = [&](UsbHidInterface type) {
165 const auto& entry = entries_[static_cast<uint8_t>(type)];
166 if (!entry.active) return;
167 defs[count++] = entry.def;
168 };
169
170 append_def(UsbHidInterface::Fido);
171 append_def(UsbHidInterface::Keyboard);
172 append_def(UsbHidInterface::Ccid);
173
174 bool replug_needed = false;
175 bool ok = usb_hid_apply_config(defs, count, &replug_needed);
176 if (!ok || replug_needed) {
177 needsReplug_ = true;
178 }
179 return ok;
180}
181
187bool UsbManager::registerMassStorage(const char* owner) {
188 if (mscActive_) {
189 if (mscOwner_ && owner && strcmp(mscOwner_, owner) == 0) return true;
190 LOG_W(TAG, "MSC already owned by %s", mscOwner_ ? mscOwner_ : "?");
191 return false;
192 }
193 if (endpointsInUse() + MSC_ENDPOINTS > MAX_ENDPOINTS) {
194 LOG_W(TAG, "USB endpoint budget exhausted for MSC (have %d/%d)",
195 endpointsInUse(), MAX_ENDPOINTS);
196 return false;
197 }
198 mscActive_ = true;
199 mscOwner_ = owner;
200 LOG_I(TAG, "Registered MSC for %s", owner ? owner : "?");
201 usb_hid_set_msc(true);
202 return true;
203}
204
209void UsbManager::unregisterMassStorage(const char* owner) {
210 if (!mscActive_) return;
211 if (mscOwner_ && owner && strcmp(mscOwner_, owner) != 0) {
212 LOG_W(TAG, "MSC owned by %s, not %s", mscOwner_, owner ? owner : "?");
213 return;
214 }
215 mscActive_ = false;
216 mscOwner_ = nullptr;
217 LOG_I(TAG, "Unregistered MSC");
218 usb_hid_set_msc(false);
219}
220
221} // namespace cdc::core
static const char * TAG
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
Definition cdc_log.h:146
#define LOG_I(tag, fmt,...)
Definition cdc_log.h:147
bool init() override
Initializes USB manager service state.
bool registerMassStorage(const char *owner)
Registers the single USB Mass Storage LUN and re-enumerates.
bool registerInterface(UsbHidInterface type, const char *moduleName, const UsbInterfaceSpec &def)
Registers a HID interface request from a module.
bool start() override
Starts USB manager service state.
void unregisterMassStorage(const char *owner)
Unregisters the MSC LUN and re-enumerates (drive disappears).
static UsbManager & instance()
Returns singleton USB manager instance.
void unregisterInterface(UsbHidInterface type, const char *moduleName)
Unregisters a previously registered HID interface.
void stop() override
Stops USB manager service state.
bool applyConfiguration()
Applies current interface set to USB HID stack.
void usb_hid_set_msc(bool active)
Adds or removes the MSC interface and re-enumerates the device.
Definition usb_hid.cpp:414
bool usb_hid_apply_config(const UsbInterfaceDef *defs, size_t count, bool *needs_replug)
Applies the runtime interface configuration and optionally triggers re-enumeration.
Definition usb_hid.cpp:388