Skip to content

Commit 72ebab0

Browse files
committed
subsys: usb: host: fix class match issue and add remove handling
Incorrect start address is used for usbh_class_connected for each supported independent class. Implement dev_removed_handler to properly notify class disconnection event. Signed-off-by: Aiden Hu <[email protected]>
1 parent c85c9f8 commit 72ebab0

File tree

1 file changed

+41
-20
lines changed

1 file changed

+41
-20
lines changed

subsys/usb/host/usbh_core.c

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ static int usbh_match_classes(struct usbh_context *const ctx,
9090
/* Step 1: Find first IAD or interface descriptor from start_addr */
9191
mask = BIT(USB_DESC_INTERFACE) | BIT(USB_DESC_INTERFACE_ASSOC);
9292

93-
desc = usbh_desc_get_by_type(start_addr, end_addr, mask);
93+
desc = usbh_desc_get_by_type(start_addr, desc_buf_end, mask);
9494
if (desc == NULL) {
9595
LOG_ERR("No IAD or interface descriptor found - error condition");
9696
break;
@@ -99,6 +99,7 @@ static int usbh_match_classes(struct usbh_context *const ctx,
9999

100100
if (desc->bDescriptorType == USB_DESC_INTERFACE_ASSOC) {
101101
found_iad = true;
102+
iad_desc = desc;
102103
}
103104

104105
if (desc->bDescriptorType == USB_DESC_INTERFACE) {
@@ -111,11 +112,11 @@ static int usbh_match_classes(struct usbh_context *const ctx,
111112
}
112113

113114
/* Step 2: Continue searching for subsequent descriptors to determine end_addr */
114-
start_addr += ((struct usb_desc_header *)start_addr)->bLength;
115+
uint8_t *search_start = start_addr + ((struct usb_desc_header *)start_addr)->bLength;
115116

116117
/* Find next IAD */
117118
mask = BIT(USB_DESC_INTERFACE_ASSOC);
118-
desc = usbh_desc_get_by_type(start_addr, end_addr, mask);
119+
desc = usbh_desc_get_by_type(search_start, desc_buf_end, mask);
119120
next_iad_addr = (uint8_t *)desc;
120121

121122
/* Handle different cases and determine end_addr and device_info. */
@@ -130,11 +131,10 @@ static int usbh_match_classes(struct usbh_context *const ctx,
130131
} else if (found_iad && next_iad_addr) {
131132
/* Case 2c: Found IAD in step 1, found new IAD in subsequent descriptors */
132133
end_addr = next_iad_addr;
133-
start_addr += iad_desc->bLength;
134134

135135
/* Get class code from first interface after IAD */
136-
mask = BIT(USB_DESC_INTERFACE_ASSOC);
137-
desc = usbh_desc_get_by_type(start_addr, end_addr, mask);
136+
mask = BIT(USB_DESC_INTERFACE);
137+
desc = usbh_desc_get_by_type(search_start, end_addr, mask);
138138
if (desc != NULL) {
139139
struct usb_if_descriptor *if_desc = (void *)desc;
140140

@@ -145,28 +145,33 @@ static int usbh_match_classes(struct usbh_context *const ctx,
145145
} else if (found_iad && !next_iad_addr) {
146146
/* Case 2d: Found IAD in step 1, no new IAD in subsequent descriptors */
147147
/* Get class code from first interface after IAD */
148-
start_addr += iad_desc->bLength;
149148
mask = BIT(USB_DESC_INTERFACE);
150-
desc = usbh_desc_get_by_type(start_addr, end_addr, mask);
149+
desc = usbh_desc_get_by_type(search_start, desc_buf_end, mask);
151150
if (desc != NULL) {
152-
struct usb_if_descriptor *if_desc = (void *)start_addr;
151+
struct usb_if_descriptor *if_desc = (void *)desc;
153152

154153
device_info.code_triple.dclass = if_desc->bInterfaceClass;
155154
device_info.code_triple.sub = if_desc->bInterfaceSubClass;
156155
device_info.code_triple.proto = if_desc->bInterfaceProtocol;
157-
}
158-
159-
/* Search for interface descriptor with different class code after IAD */
160-
start_addr += iad_desc->bLength;
161-
mask = BIT(USB_DESC_INTERFACE);
162-
desc = usbh_desc_get_by_type(start_addr, desc_buf_end, mask);
163-
if (desc != NULL) {
164-
struct usb_if_descriptor *if_desc = (void *)desc;
165156

166-
/* Only compare class code */
167-
if (if_desc->bInterfaceClass != device_info.code_triple.dclass) {
157+
/* Search for interface descriptor with different class code after IAD */
158+
uint8_t *next_search = (uint8_t *)desc + desc->bLength;
159+
mask = BIT(USB_DESC_INTERFACE);
160+
desc = usbh_desc_get_by_type(next_search, desc_buf_end, mask);
161+
if (desc != NULL) {
162+
struct usb_if_descriptor *if_desc = (void *)desc;
163+
164+
/* Only compare class code */
165+
if (if_desc->bInterfaceClass != device_info.code_triple.dclass) {
166+
end_addr = (uint8_t *)desc;
167+
} else {
168+
end_addr = desc_buf_end;
169+
}
170+
} else {
168171
end_addr = desc_buf_end;
169172
}
173+
} else {
174+
end_addr = desc_buf_end;
170175
}
171176
}
172177

@@ -185,7 +190,7 @@ static int usbh_match_classes(struct usbh_context *const ctx,
185190
cdata->name, device_info.code_triple.dclass);
186191

187192
/* Step 4: Call connected handler */
188-
int ret = usbh_class_connected(cdata, start_addr, end_addr);
193+
int ret = usbh_class_connected(udev, cdata, start_addr, end_addr);
189194
if (ret == 0) {
190195
LOG_INF("Class driver %s successfully claimed device", cdata->name);
191196
matched = true;
@@ -256,6 +261,22 @@ static void dev_connected_handler(struct usbh_context *const ctx,
256261
static void dev_removed_handler(struct usbh_context *const ctx)
257262
{
258263
if (ctx->root != NULL) {
264+
LOG_DBG("Device removed - notifying class drivers");
265+
266+
/* Notify all relevant class drivers that device is disconnected */
267+
struct usbh_class_data *cdata;
268+
SYS_SLIST_FOR_EACH_CONTAINER(&ctx->class_list, cdata, node) {
269+
LOG_DBG("Calling disconnected for class driver: %s", cdata->name);
270+
int ret = usbh_class_removed(ctx->root, cdata);
271+
if (ret != 0) {
272+
LOG_WRN("Class driver %s disconnected callback failed: %d",
273+
cdata->name, ret);
274+
} else {
275+
LOG_INF("Class driver %s successfully disconnected", cdata->name);
276+
}
277+
}
278+
279+
/* Free device resources */
259280
usbh_device_free(ctx->root);
260281
ctx->root = NULL;
261282
LOG_DBG("Device removed");

0 commit comments

Comments
 (0)