@@ -43,6 +43,258 @@ static int usbh_event_carrier(const struct device *dev,
43
43
return err ;
44
44
}
45
45
46
+ /**
47
+ * @brief Check if USB device matches class driver
48
+ *
49
+ * @param cdata Pointer to class driver data
50
+ * @param code Pointer to USB class code triple
51
+ * @return true if matched, false otherwise
52
+ */
53
+ static bool usbh_match_class_driver (struct usbh_class_data * cdata ,
54
+ struct usbh_code_triple * code )
55
+ {
56
+ if (!cdata || !code || !cdata -> device_code_table ) {
57
+ return false;
58
+ }
59
+
60
+ /* Traverse device code table (cdata->device_code_table) */
61
+ for (int i = 0 ; i < cdata -> table_items_count ; i ++ ) {
62
+ struct usbh_device_code_table * table_entry = & cdata -> device_code_table [i ];
63
+ /* TODO: match device code */
64
+
65
+ if (table_entry -> match_type & USBH_MATCH_INTFACE ) {
66
+ /* Match interface class code */
67
+ if (table_entry -> interface_class_code == code -> dclass &&
68
+ (table_entry -> interface_subclass_code == 0xFF ||
69
+ table_entry -> interface_subclass_code == code -> sub ) &&
70
+ (table_entry -> interface_protocol_code == 0x00 ||
71
+ table_entry -> interface_protocol_code == code -> proto )) {
72
+ return true;
73
+ }
74
+ }
75
+ }
76
+
77
+ return false;
78
+ }
79
+
80
+ /**
81
+ * @brief Enumerate device descriptors and match class drivers
82
+ *
83
+ * This function traverses the USB device descriptors, identifies class-specific
84
+ * descriptor segments, and attempts to match them with registered class drivers.
85
+ *
86
+ * @param ctx USB host context
87
+ * @param udev USB device to process
88
+ * @return 0 on success, negative errno on failure
89
+ */
90
+ static int usbh_match_classes (struct usbh_contex * const ctx ,
91
+ struct usb_device * udev )
92
+ {
93
+ struct usb_cfg_descriptor * cfg_desc = udev -> cfg_desc ;
94
+
95
+ if (!cfg_desc ) {
96
+ LOG_ERR ("No configuration descriptor found" );
97
+ return - EINVAL ;
98
+ }
99
+
100
+ uint8_t * desc_buf_base = (uint8_t * )cfg_desc ;
101
+ uint8_t * desc_buf_end = desc_buf_base + sys_le16_to_cpu (cfg_desc -> wTotalLength );
102
+ uint8_t * current_desc = desc_buf_base + cfg_desc -> bLength ; /* Skip config descriptor */
103
+ int matched_count = 0 ;
104
+
105
+ LOG_DBG ("Starting class enumeration for device (total desc length: %d)" ,
106
+ sys_le16_to_cpu (cfg_desc -> wTotalLength ));
107
+
108
+ /* Main descriptor traversal loop - traverse entire descriptor */
109
+ while (current_desc < desc_buf_end ) {
110
+ uint8_t * start_addr = current_desc ; /* Initialize to current descriptor */
111
+ uint8_t * end_addr = current_desc ; /* Initialize to current descriptor */
112
+ uint8_t * search_ptr ;
113
+ struct usbh_code_triple class_code = {0 };
114
+ bool found_iad = false;
115
+ bool found_interface = false;
116
+ struct usb_desc_header * iad_desc = NULL ;
117
+
118
+ /* Step 1: Find first IAD or interface descriptor from start_addr */
119
+ search_ptr = start_addr ;
120
+ while (search_ptr < desc_buf_end ) {
121
+ struct usb_desc_header * header = (struct usb_desc_header * )search_ptr ;
122
+
123
+ if (header -> bLength == 0 ) {
124
+ goto exit_loop ;
125
+ }
126
+
127
+ if (header -> bDescriptorType == USB_DESC_INTERFACE_ASSOC ) {
128
+ start_addr = search_ptr ;
129
+ found_iad = true;
130
+ iad_desc = search_ptr ;
131
+ break ;
132
+ } else if (header -> bDescriptorType == USB_DESC_INTERFACE ) {
133
+ start_addr = search_ptr ;
134
+ found_interface = true;
135
+ /* Save class code for interface */
136
+ struct usb_if_descriptor * if_desc = (struct usb_if_descriptor * )search_ptr ;
137
+ class_code .dclass = if_desc -> bInterfaceClass ;
138
+ class_code .sub = if_desc -> bInterfaceSubClass ;
139
+ class_code .proto = if_desc -> bInterfaceProtocol ;
140
+ break ;
141
+ }
142
+
143
+ search_ptr += header -> bLength ;
144
+ }
145
+
146
+ /* If no IAD or interface found, exit main loop (error condition) */
147
+ if (!found_iad && !found_interface ) {
148
+ LOG_ERR ("No IAD or interface descriptor found - error condition" );
149
+ break ;
150
+ }
151
+
152
+ /* Step 2: Continue searching for subsequent descriptors to determine end_addr */
153
+ search_ptr = start_addr + ((struct usb_desc_header * )start_addr )-> bLength ;
154
+ uint8_t * next_iad_addr = NULL ;
155
+
156
+ /* Find next IAD */
157
+ while (search_ptr < desc_buf_end ) {
158
+ struct usb_desc_header * header = (struct usb_desc_header * )search_ptr ;
159
+
160
+ if (header -> bLength == 0 ) {
161
+ break ;
162
+ }
163
+
164
+ if (header -> bDescriptorType == USB_DESC_INTERFACE_ASSOC ) {
165
+ next_iad_addr = search_ptr ;
166
+ break ;
167
+ }
168
+
169
+ search_ptr += header -> bLength ;
170
+ }
171
+
172
+ /* Handle different cases and determine end_addr and class_code */
173
+ if (!found_iad && !next_iad_addr ) {
174
+ /* Case 2a: No IAD in step 1, no IAD in subsequent descriptors */
175
+ end_addr = desc_buf_end ;
176
+ /* class_code already saved in step 1 */
177
+ } else if (!found_iad && next_iad_addr ) {
178
+ /* Case 2b: No IAD in step 1, found new IAD in subsequent descriptors */
179
+ end_addr = next_iad_addr ;
180
+ /* class_code already saved in step 1 */
181
+ } else if (found_iad && next_iad_addr ) {
182
+ /* Case 2c: Found IAD in step 1, found new IAD in subsequent descriptors */
183
+ end_addr = next_iad_addr ;
184
+ /* Get class code from first interface after IAD */
185
+ search_ptr = start_addr + iad_desc -> bLength ;
186
+ while (search_ptr < end_addr ) {
187
+ struct usb_desc_header * header = (struct usb_desc_header * )search_ptr ;
188
+ if (header -> bLength == 0 ) {
189
+ break ;
190
+ }
191
+ if (header -> bDescriptorType == USB_DESC_INTERFACE ) {
192
+ struct usb_if_descriptor * if_desc = (struct usb_if_descriptor * )search_ptr ;
193
+ class_code .dclass = if_desc -> bInterfaceClass ;
194
+ class_code .sub = if_desc -> bInterfaceSubClass ;
195
+ class_code .proto = if_desc -> bInterfaceProtocol ;
196
+ break ;
197
+ }
198
+ search_ptr += header -> bLength ;
199
+ }
200
+ } else if (found_iad && !next_iad_addr ) {
201
+ /* Case 2d: Found IAD in step 1, no new IAD in subsequent descriptors */
202
+ /* Get class code from first interface after IAD */
203
+ search_ptr = start_addr + iad_desc -> bLength ;
204
+ while (search_ptr < desc_buf_end ) {
205
+ struct usb_desc_header * header = (struct usb_desc_header * )search_ptr ;
206
+ if (header -> bLength == 0 ) {
207
+ break ;
208
+ }
209
+ if (header -> bDescriptorType == USB_DESC_INTERFACE ) {
210
+ struct usb_if_descriptor * if_desc = (struct usb_if_descriptor * )search_ptr ;
211
+ class_code .dclass = if_desc -> bInterfaceClass ;
212
+ class_code .sub = if_desc -> bInterfaceSubClass ;
213
+ class_code .proto = if_desc -> bInterfaceProtocol ;
214
+ break ;
215
+ }
216
+ search_ptr += header -> bLength ;
217
+ }
218
+
219
+ /* Search for interface descriptor with different class code after IAD */
220
+ search_ptr = start_addr + iad_desc -> bLength ;
221
+ bool found_different_interface = false;
222
+
223
+ while (search_ptr < desc_buf_end ) {
224
+ struct usb_desc_header * header = (struct usb_desc_header * )search_ptr ;
225
+ if (header -> bLength == 0 ) {
226
+ break ;
227
+ }
228
+
229
+ if (header -> bDescriptorType == USB_DESC_INTERFACE ) {
230
+ struct usb_if_descriptor * if_desc = (struct usb_if_descriptor * )search_ptr ;
231
+ /* Only compare class code */
232
+ if (if_desc -> bInterfaceClass != class_code .dclass ) {
233
+ end_addr = search_ptr ;
234
+ found_different_interface = true;
235
+ break ;
236
+ }
237
+ }
238
+ search_ptr += header -> bLength ;
239
+ }
240
+
241
+ if (!found_different_interface ) {
242
+ end_addr = desc_buf_end ;
243
+ }
244
+ }
245
+
246
+ LOG_DBG ("Found class segment: class=0x%02x, sub=0x%02x, proto=0x%02x, start=%p, end=%p" ,
247
+ class_code .dclass , class_code .sub , class_code .proto ,
248
+ start_addr , end_addr );
249
+
250
+ /* Step 3: Loop through registered class drivers and call usbh_match_class_driver */
251
+ struct usbh_class_data * cdata ;
252
+ bool matched = false;
253
+
254
+ SYS_SLIST_FOR_EACH_CONTAINER (& ctx -> registered_classes , cdata , node ) {
255
+ if (!cdata -> api || !cdata -> api -> connected ) {
256
+ continue ;
257
+ }
258
+
259
+ /* Call usbh_match_class_driver with cdata and code */
260
+ if (usbh_match_class_driver (cdata , & class_code )) {
261
+ LOG_INF ("Class driver %s matched for class 0x%02x" ,
262
+ cdata -> name , class_code .dclass );
263
+
264
+ /* Step 4: Call connected handler */
265
+ int ret = cdata -> api -> connected (udev , start_addr , end_addr , (void * )cdata );
266
+ if (ret == 0 ) {
267
+ LOG_INF ("Class driver %s successfully claimed device" , cdata -> name );
268
+ matched = true;
269
+ matched_count ++ ;
270
+ } else {
271
+ LOG_WRN ("Class driver %s failed to claim device: %d" ,
272
+ cdata -> name , ret );
273
+ }
274
+ }
275
+ }
276
+
277
+ if (!matched ) {
278
+ LOG_DBG ("No class driver matched for class 0x%02x" , class_code .dclass );
279
+ }
280
+
281
+ /* Step 4: assign end_addr to current_desc and continue main loop */
282
+ current_desc = end_addr ;
283
+
284
+ /* Ensure we advance to next valid descriptor */
285
+ if (current_desc < desc_buf_end ) {
286
+ struct usb_desc_header * header = (struct usb_desc_header * )current_desc ;
287
+ if (header -> bLength == 0 ) {
288
+ break ;
289
+ }
290
+ }
291
+ }
292
+
293
+ exit_loop :
294
+ LOG_INF ("Class enumeration completed: %d driver(s) matched" , matched_count );
295
+ return 0 ;
296
+ }
297
+
46
298
static void dev_connected_handler (struct usbh_contex * const ctx ,
47
299
const struct uhc_event * const event )
48
300
{
@@ -71,6 +323,11 @@ static void dev_connected_handler(struct usbh_contex *const ctx,
71
323
if (usbh_device_init (ctx -> root )) {
72
324
LOG_ERR ("Failed to reset new USB device" );
73
325
}
326
+
327
+ /* Now only consider about one device connected (root device) */
328
+ if (usbh_match_classes (ctx , ctx -> root )) {
329
+ LOG_ERR ("Failed to match classes" );
330
+ }
74
331
}
75
332
76
333
static void dev_removed_handler (struct usbh_contex * const ctx )
@@ -182,6 +439,41 @@ static void usbh_thread(void *p1, void *p2, void *p3)
182
439
}
183
440
}
184
441
442
+ /**
443
+ * @brief Auto-register all compile-time defined class drivers
444
+ */
445
+ static int usbh_register_all_classes (struct usbh_contex * uhs_ctx )
446
+ {
447
+ int registered_count = 0 ;
448
+
449
+ STRUCT_SECTION_FOREACH (usbh_class_data , cdata ) {
450
+ /* Check if already registered */
451
+ struct usbh_class_data * existing ;
452
+ bool already_registered = false;
453
+
454
+ SYS_SLIST_FOR_EACH_CONTAINER (& uhs_ctx -> registered_classes , existing , node ) {
455
+ if (existing == cdata ) {
456
+ already_registered = true;
457
+ break ;
458
+ }
459
+ }
460
+
461
+ if (!already_registered ) {
462
+ sys_slist_append (& uhs_ctx -> registered_classes , & cdata -> node );
463
+ registered_count ++ ;
464
+ LOG_DBG ("Auto-registered class: %s" , cdata -> name );
465
+ }
466
+ }
467
+
468
+ LOG_INF ("Auto-registered %d classes to controller %s" ,
469
+ registered_count , uhs_ctx -> name );
470
+
471
+ return 0 ;
472
+ }
473
+
474
+ /**
475
+ * @brief Initialize USB host controller and class drivers
476
+ */
185
477
int usbh_init_device_intl (struct usbh_contex * const uhs_ctx )
186
478
{
187
479
int ret ;
@@ -193,13 +485,25 @@ int usbh_init_device_intl(struct usbh_contex *const uhs_ctx)
193
485
}
194
486
195
487
sys_dlist_init (& uhs_ctx -> udevs );
488
+ sys_slist_init (& uhs_ctx -> registered_classes );
196
489
197
- STRUCT_SECTION_FOREACH (usbh_class_data , cdata ) {
198
- /*
199
- * For now, we have not implemented any class drivers,
200
- * so just keep it as placeholder.
201
- */
202
- break ;
490
+ /* Register all class drivers */
491
+ ret = usbh_register_all_classes (uhs_ctx );
492
+ if (ret != 0 ) {
493
+ LOG_WRN ("Failed to auto-register classes" );
494
+ }
495
+
496
+ /* Initialize registered class drivers */
497
+ struct usbh_class_data * cdata ;
498
+ SYS_SLIST_FOR_EACH_CONTAINER (& uhs_ctx -> registered_classes , cdata , node ) {
499
+ if (cdata -> api && cdata -> api -> init ) {
500
+ ret = cdata -> api -> init (uhs_ctx , cdata );
501
+ if (ret != 0 ) {
502
+ LOG_WRN ("Failed to init class driver %s" , cdata -> name );
503
+ } else {
504
+ LOG_INF ("Class driver %s initialized" , cdata -> name );
505
+ }
506
+ }
203
507
}
204
508
205
509
return 0 ;
@@ -226,4 +530,4 @@ static int uhs_pre_init(void)
226
530
return 0 ;
227
531
}
228
532
229
- SYS_INIT (uhs_pre_init , POST_KERNEL , CONFIG_USBH_INIT_PRIO );
533
+ SYS_INIT (uhs_pre_init , POST_KERNEL , CONFIG_USBH_INIT_PRIO );
0 commit comments