1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <ddk/debug.h>
6 #include <ddk/metadata.h>
7 #include <usb/usb.h>
8 #include <zircon/hw/usb/audio.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include "usb-composite.h"
14 #include "usb-interface.h"
15 
16 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
17 
18 #define NEXT_DESCRIPTOR(header) ((usb_descriptor_header_t*)((void*)header + header->bLength))
19 
20 // returns whether the interface with the given id was removed.
usb_composite_remove_interface_by_id_locked(usb_composite_t * comp,uint8_t interface_id)21 static bool usb_composite_remove_interface_by_id_locked(usb_composite_t* comp,
22                                                         uint8_t interface_id) {
23     usb_interface_t* intf;
24     usb_interface_t* tmp;
25 
26     list_for_every_entry_safe(&comp->children, intf, tmp, usb_interface_t, node) {
27         if (usb_interface_contains_interface(intf, interface_id)) {
28             list_delete(&intf->node);
29             device_remove(intf->zxdev);
30             return true;
31         }
32     }
33     return false;
34 }
35 
usb_composite_add_interface(usb_composite_t * comp,usb_interface_descriptor_t * interface_desc,size_t interface_desc_length)36 static zx_status_t usb_composite_add_interface(usb_composite_t* comp,
37                                                usb_interface_descriptor_t* interface_desc,
38                                                size_t interface_desc_length) {
39     usb_device_descriptor_t* device_desc = &comp->device_desc;
40     usb_interface_t* intf = calloc(1, sizeof(usb_interface_t));
41     if (!intf) {
42         free(interface_desc);
43         return ZX_ERR_NO_MEMORY;
44     }
45 
46     intf->comp = comp;
47     intf->last_interface_id = interface_desc->bInterfaceNumber;
48     intf->descriptor = (usb_descriptor_header_t *)interface_desc;
49     intf->descriptor_length = interface_desc_length;
50 
51     uint8_t usb_class, usb_subclass, usb_protocol;
52     if (interface_desc->bInterfaceClass == 0) {
53         usb_class = device_desc->bDeviceClass;
54         usb_subclass = device_desc->bDeviceSubClass;
55         usb_protocol = device_desc->bDeviceProtocol;
56     } else {
57         // class/subclass/protocol defined per-interface
58         usb_class = interface_desc->bInterfaceClass;
59         usb_subclass = interface_desc->bInterfaceSubClass;
60         usb_protocol = interface_desc->bInterfaceProtocol;
61    }
62 
63     zx_status_t status = usb_interface_configure_endpoints(intf, interface_desc->bInterfaceNumber,
64                                                            0);
65     if (status != ZX_OK) {
66         free(interface_desc);
67         free(intf);
68         return status;
69     }
70 
71     mtx_lock(&comp->interface_mutex);
72     // need to do this first so usb_composite_set_interface() can be called from driver bind
73     list_add_head(&comp->children, &intf->node);
74     mtx_unlock(&comp->interface_mutex);
75 
76     char name[20];
77     snprintf(name, sizeof(name), "ifc-%03d", interface_desc->bInterfaceNumber);
78 
79     zx_device_prop_t props[] = {
80         { BIND_PROTOCOL, 0, ZX_PROTOCOL_USB },
81         { BIND_USB_VID, 0, device_desc->idVendor },
82         { BIND_USB_PID, 0, device_desc->idProduct },
83         { BIND_USB_CLASS, 0, usb_class },
84         { BIND_USB_SUBCLASS, 0, usb_subclass },
85         { BIND_USB_PROTOCOL, 0, usb_protocol },
86     };
87 
88     device_add_args_t args = {
89         .version = DEVICE_ADD_ARGS_VERSION,
90         .name = name,
91         .ctx = intf,
92         .ops = &usb_interface_proto,
93         .proto_id = ZX_PROTOCOL_USB,
94         .proto_ops = &usb_device_protocol,
95         .props = props,
96         .prop_count = countof(props),
97     };
98 
99     status = device_add(comp->zxdev, &args, &intf->zxdev);
100     if (status != ZX_OK) {
101         list_delete(&intf->node);
102         free(interface_desc);
103         free(intf);
104     }
105     return status;
106 }
107 
usb_composite_add_interface_assoc(usb_composite_t * comp,usb_interface_assoc_descriptor_t * assoc_desc,size_t assoc_desc_length)108 static zx_status_t usb_composite_add_interface_assoc(usb_composite_t* comp,
109                                                      usb_interface_assoc_descriptor_t* assoc_desc,
110                                                      size_t assoc_desc_length) {
111     usb_device_descriptor_t* device_desc = &comp->device_desc;
112     usb_interface_t* intf = calloc(1, sizeof(usb_interface_t));
113     if (!intf) {
114         return ZX_ERR_NO_MEMORY;
115     }
116 
117     intf->comp = comp;
118     // Interfaces in an IAD interface collection must be contiguous.
119     intf->last_interface_id = assoc_desc->bFirstInterface + assoc_desc->bInterfaceCount - 1;
120     intf->descriptor = (usb_descriptor_header_t *)assoc_desc;
121     intf->descriptor_length = assoc_desc_length;
122 
123     uint8_t usb_class, usb_subclass, usb_protocol;
124     if (assoc_desc->bFunctionClass == 0) {
125         usb_class = device_desc->bDeviceClass;
126         usb_subclass = device_desc->bDeviceSubClass;
127         usb_protocol = device_desc->bDeviceProtocol;
128     } else {
129         // class/subclass/protocol defined per-interface
130         usb_class = assoc_desc->bFunctionClass;
131         usb_subclass = assoc_desc->bFunctionSubClass;
132         usb_protocol = assoc_desc->bFunctionProtocol;
133    }
134 
135     usb_descriptor_header_t* header = intf->descriptor;
136     usb_descriptor_header_t* end = (usb_descriptor_header_t*)((void*)header +
137                                                               intf->descriptor_length);
138     while (header < end) {
139         if (header->bDescriptorType == USB_DT_INTERFACE) {
140             usb_interface_descriptor_t* intf_desc = (usb_interface_descriptor_t*)header;
141             if (intf_desc->bAlternateSetting == 0) {
142                 zx_status_t status = usb_interface_configure_endpoints(intf,
143                                                                        intf_desc->bInterfaceNumber,
144                                                                        0);
145                 if (status != ZX_OK) {
146                     return status;
147                 }
148             }
149         }
150         header = NEXT_DESCRIPTOR(header);
151     }
152 
153     mtx_lock(&comp->interface_mutex);
154     // need to do this first so usb_composite_set_interface() can be called from driver bind
155     list_add_head(&comp->children, &intf->node);
156     mtx_unlock(&comp->interface_mutex);
157 
158     char name[20];
159     snprintf(name, sizeof(name), "asc-%03d", assoc_desc->iFunction);
160 
161     zx_device_prop_t props[] = {
162         { BIND_PROTOCOL, 0, ZX_PROTOCOL_USB },
163         { BIND_USB_VID, 0, device_desc->idVendor },
164         { BIND_USB_PID, 0, device_desc->idProduct },
165         { BIND_USB_CLASS, 0, usb_class },
166         { BIND_USB_SUBCLASS, 0, usb_subclass },
167         { BIND_USB_PROTOCOL, 0, usb_protocol },
168     };
169 
170     device_add_args_t args = {
171         .version = DEVICE_ADD_ARGS_VERSION,
172         .name = name,
173         .ctx = intf,
174         .ops = &usb_interface_proto,
175         .proto_id = ZX_PROTOCOL_USB,
176         .proto_ops = &usb_device_protocol,
177         .props = props,
178         .prop_count = countof(props),
179     };
180 
181     zx_status_t status = device_add(comp->zxdev, &args, &intf->zxdev);
182     if (status != ZX_OK) {
183         list_delete(&intf->node);
184         free(assoc_desc);
185         free(intf);
186     }
187     return status;
188 }
189 
usb_composite_add_interfaces(usb_composite_t * comp)190 static zx_status_t usb_composite_add_interfaces(usb_composite_t* comp) {
191     usb_configuration_descriptor_t* config = comp->config_desc;
192 
193     comp->interface_statuses = calloc(config->bNumInterfaces, sizeof(interface_status_t));
194     if (!comp->interface_statuses) {
195         return ZX_ERR_NO_MEMORY;
196     }
197 
198     // Iterate through interfaces in first configuration and create devices for them
199     usb_descriptor_header_t* header = NEXT_DESCRIPTOR(config);
200     usb_descriptor_header_t* end = (usb_descriptor_header_t*)((void*)config +
201                                                                 le16toh(config->wTotalLength));
202 
203     zx_status_t result = ZX_OK;
204 
205     while (header < end) {
206         if (header->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) {
207             usb_interface_assoc_descriptor_t* assoc_desc =
208                                                     (usb_interface_assoc_descriptor_t*)header;
209             int interface_count = assoc_desc->bInterfaceCount;
210 
211             // find end of this interface association
212             usb_descriptor_header_t* next = NEXT_DESCRIPTOR(assoc_desc);
213             while (next < end) {
214                 if (next->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) {
215                     break;
216                 } else if (next->bDescriptorType == USB_DT_INTERFACE) {
217                     usb_interface_descriptor_t* test_intf = (usb_interface_descriptor_t*)next;
218 
219                     if (test_intf->bAlternateSetting == 0) {
220                         if (interface_count == 0) {
221                             break;
222                         }
223                         interface_count--;
224                     }
225                 }
226                 next = NEXT_DESCRIPTOR(next);
227             }
228 
229             size_t length = (void *)next - (void *)assoc_desc;
230             usb_interface_assoc_descriptor_t* assoc_copy = malloc(length);
231             if (!assoc_copy) return ZX_ERR_NO_MEMORY;
232             memcpy(assoc_copy, assoc_desc, length);
233 
234             zx_status_t status = usb_composite_add_interface_assoc(comp, assoc_copy, length);
235             if (status != ZX_OK) {
236                 result = status;
237             }
238 
239             header = next;
240         } else if (header->bDescriptorType == USB_DT_INTERFACE) {
241             usb_interface_descriptor_t* intf_desc = (usb_interface_descriptor_t*)header;
242             // find end of current interface descriptor
243             usb_descriptor_header_t* next = NEXT_DESCRIPTOR(intf_desc);
244             while (next < end) {
245                 if (next->bDescriptorType == USB_DT_INTERFACE) {
246                     usb_interface_descriptor_t* test_intf = (usb_interface_descriptor_t*)next;
247                     // Iterate until we find the next top-level interface
248                     // Include alternate interfaces in the current interface
249                     if (test_intf->bAlternateSetting == 0) {
250                         break;
251                     }
252                 }
253                 next = NEXT_DESCRIPTOR(next);
254             }
255 
256             // Only create a child device if no child interface has claimed this interface.
257             mtx_lock(&comp->interface_mutex);
258             interface_status_t intf_status = comp->interface_statuses[intf_desc->bInterfaceNumber];
259             mtx_unlock(&comp->interface_mutex);
260 
261             size_t length = (void *)next - (void *)intf_desc;
262             if (intf_status == AVAILABLE) {
263                 usb_interface_descriptor_t* intf_copy = malloc(length);
264                 if (!intf_copy) return ZX_ERR_NO_MEMORY;
265                 memcpy(intf_copy, intf_desc, length);
266                 zx_status_t status = usb_composite_add_interface(comp, intf_copy, length);
267                 if (status != ZX_OK) {
268                     result = status;
269                 }
270                 // The interface may have been claimed in the meanwhile, so we need to
271                 // check the interface status again.
272                 mtx_lock(&comp->interface_mutex);
273                 if (comp->interface_statuses[intf_desc->bInterfaceNumber] == CLAIMED) {
274                     bool removed = usb_composite_remove_interface_by_id_locked(comp,
275                                                                     intf_desc->bInterfaceNumber);
276                     if (!removed) {
277                         mtx_unlock(&comp->interface_mutex);
278                         return ZX_ERR_BAD_STATE;
279                     }
280                 } else {
281                     comp->interface_statuses[intf_desc->bInterfaceNumber] = CHILD_DEVICE;
282                 }
283                 mtx_unlock(&comp->interface_mutex);
284             }
285             header = next;
286         } else {
287             header = NEXT_DESCRIPTOR(header);
288         }
289     }
290 
291     return result;
292 }
293 
usb_composite_remove_interfaces(usb_composite_t * comp)294 static void usb_composite_remove_interfaces(usb_composite_t* comp) {
295     mtx_lock(&comp->interface_mutex);
296 
297     usb_interface_t* intf;
298     while ((intf = list_remove_head_type(&comp->children, usb_interface_t, node)) != NULL) {
299         device_remove(intf->zxdev);
300     }
301     free(comp->interface_statuses);
302     comp->interface_statuses = NULL;
303 
304     mtx_unlock(&comp->interface_mutex);
305 }
306 
usb_composite_do_claim_interface(usb_composite_t * comp,uint8_t interface_id)307 zx_status_t usb_composite_do_claim_interface(usb_composite_t* comp, uint8_t interface_id) {
308     mtx_lock(&comp->interface_mutex);
309 
310     interface_status_t status = comp->interface_statuses[interface_id];
311     if (status == CLAIMED) {
312         // The interface has already been claimed by a different interface.
313         mtx_unlock(&comp->interface_mutex);
314         return ZX_ERR_ALREADY_BOUND;
315     } else if (status == CHILD_DEVICE) {
316         bool removed = usb_composite_remove_interface_by_id_locked(comp, interface_id);
317         if (!removed) {
318             mtx_unlock(&comp->interface_mutex);
319             return ZX_ERR_BAD_STATE;
320         }
321     }
322     comp->interface_statuses[interface_id] = CLAIMED;
323 
324     mtx_unlock(&comp->interface_mutex);
325 
326     return ZX_OK;
327 }
328 
usb_composite_set_interface(usb_composite_t * comp,uint8_t interface_id,uint8_t alt_setting)329 zx_status_t usb_composite_set_interface(usb_composite_t* comp, uint8_t interface_id,
330                                         uint8_t alt_setting) {
331     mtx_lock(&comp->interface_mutex);
332     usb_interface_t* intf;
333     list_for_every_entry(&comp->children, intf, usb_interface_t, node) {
334         if (usb_interface_contains_interface(intf, interface_id)) {
335             mtx_unlock(&comp->interface_mutex);
336             return usb_interface_set_alt_setting(intf, interface_id, alt_setting);
337         }
338     }
339     mtx_unlock(&comp->interface_mutex);
340     return ZX_ERR_INVALID_ARGS;
341 }
342 
usb_composite_unbind(void * ctx)343 static void usb_composite_unbind(void* ctx) {
344     usb_composite_t* comp = ctx;
345     usb_composite_remove_interfaces(comp);
346     device_remove(comp->zxdev);
347 }
348 
usb_composite_release(void * ctx)349 static void usb_composite_release(void* ctx) {
350     usb_composite_t* comp = ctx;
351 
352     free(comp->config_desc);
353     free(comp->interface_statuses);
354     free(comp);
355 }
356 
357 static zx_protocol_device_t usb_composite_device_proto = {
358     .version = DEVICE_OPS_VERSION,
359     .unbind = usb_composite_unbind,
360     .release = usb_composite_release,
361 };
362 
usb_composite_bind(void * ctx,zx_device_t * parent)363 static zx_status_t usb_composite_bind(void* ctx, zx_device_t* parent) {
364     usb_protocol_t usb;
365     zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_USB, &usb);
366     if (status != ZX_OK) {
367         return status;
368     }
369 
370     usb_composite_t* comp = calloc(1, sizeof(usb_composite_t));
371     if (!comp) {
372         return ZX_ERR_NO_MEMORY;
373     }
374     memcpy(&comp->usb, &usb, sizeof(comp->usb));
375 
376     list_initialize(&comp->children);
377 
378     mtx_init(&comp->interface_mutex, mtx_plain);
379 
380     usb_get_device_descriptor(&usb, &comp->device_desc);
381 
382     uint8_t configuration = usb_get_configuration(&comp->usb);
383     size_t config_length;
384     status = usb_get_configuration_descriptor_length(&comp->usb, configuration, &config_length);
385     if (status != ZX_OK) {
386         return status;
387     }
388     comp->config_desc = malloc(config_length);
389     if (!comp->config_desc) {
390         return ZX_ERR_NO_MEMORY;
391     }
392     size_t actual;
393     status = usb_get_configuration_descriptor(&comp->usb, configuration,
394                                               comp->config_desc, config_length, &actual);
395     if (status != ZX_OK) {
396         goto error_exit;
397     }
398 
399     char name[16];
400     snprintf(name, sizeof(name), "%03d", usb_get_device_id(&usb));
401 
402     device_add_args_t args = {
403         .version = DEVICE_ADD_ARGS_VERSION,
404         .name = name,
405         .ctx = comp,
406         .ops = &usb_composite_device_proto,
407         .flags = DEVICE_ADD_NON_BINDABLE,
408     };
409 
410     status = device_add(parent, &args, &comp->zxdev);
411     if (status == ZX_OK) {
412         return usb_composite_add_interfaces(comp);
413     }
414 
415 error_exit:
416     free(comp->config_desc);
417     free(comp);
418     return status;
419 }
420 
421 static zx_driver_ops_t usb_composite_driver_ops = {
422     .version = DRIVER_OPS_VERSION,
423     .bind = usb_composite_bind,
424 };
425 
426 // The '*' in the version string is important. This marks this driver as a fallback,
427 // to allow other drivers to bind against ZX_PROTOCOL_USB_DEVICE to handle more specific cases.
428 ZIRCON_DRIVER_BEGIN(usb_composite, usb_composite_driver_ops, "zircon", "*0.1", 1)
429     BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_USB_DEVICE),
430 ZIRCON_DRIVER_END(usb_composite)
431