Lines Matching +full:composite +full:- +full:in
2 * composite.c - infrastructure for Composite USB Gadgets
4 * Copyright (C) 2006-2008 David Brownell
5 * U-Boot porting: Lukasz Majewski <l.majewski@samsung.com>
7 * SPDX-License-Identifier: GPL-2.0+
12 #include <linux/usb/composite.h>
19 static struct usb_composite_driver *composite; variable
23 var->val = cpu_to_le16(le16_to_cpu(var->val) + val); in le16_add_cpu_packed()
27 * usb_add_function() - add a function to a configuration
43 int value = -EINVAL; in usb_add_function()
46 function->name, function, in usb_add_function()
47 config->label, config); in usb_add_function()
49 if (!function->set_alt || !function->disable) in usb_add_function()
52 function->config = config; in usb_add_function()
53 list_add_tail(&function->list, &config->functions); in usb_add_function()
55 if (function->bind) { in usb_add_function()
56 value = function->bind(config, function); in usb_add_function()
58 list_del(&function->list); in usb_add_function()
59 function->config = NULL; in usb_add_function()
64 if (!config->fullspeed && function->descriptors) in usb_add_function()
65 config->fullspeed = 1; in usb_add_function()
66 if (!config->highspeed && function->hs_descriptors) in usb_add_function()
67 config->highspeed = 1; in usb_add_function()
68 if (!config->superspeed && function->ss_descriptors) in usb_add_function()
69 config->superspeed = 1; in usb_add_function()
73 debug("adding '%s'/%p --> %d\n", in usb_add_function()
74 function->name, function, value); in usb_add_function()
79 * usb_function_deactivate - prevent function and gadget enumeration
99 struct usb_composite_dev *cdev = function->config->cdev; in usb_function_deactivate()
102 if (cdev->deactivations == 0) in usb_function_deactivate()
103 status = usb_gadget_disconnect(cdev->gadget); in usb_function_deactivate()
105 cdev->deactivations++; in usb_function_deactivate()
111 * usb_function_activate - allow function and gadget enumeration
122 struct usb_composite_dev *cdev = function->config->cdev; in usb_function_activate()
125 if (cdev->deactivations == 0) in usb_function_activate()
126 status = -EINVAL; in usb_function_activate()
128 cdev->deactivations--; in usb_function_activate()
129 if (cdev->deactivations == 0) in usb_function_activate()
130 status = usb_gadget_connect(cdev->gadget); in usb_function_activate()
137 * usb_interface_id() - allocate an unused interface ID
144 * ID in interface, association, CDC union, and other descriptors. It
147 * also be class-specific or vendor-specific requests to handle.
152 * identifers are configuration-specific, functions used in more than
153 * one configuration (or more than once in a given configuration) need
156 * Returns the interface ID which was allocated; or -ENODEV if no
162 unsigned char id = config->next_interface_id; in usb_interface_id()
165 config->interface[id] = function; in usb_interface_id()
166 config->next_interface_id = id + 1; in usb_interface_id()
169 return -ENODEV; in usb_interface_id()
175 int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; in config_buf()
184 c->bLength = USB_DT_CONFIG_SIZE; in config_buf()
185 c->bDescriptorType = type; in config_buf()
187 c->bNumInterfaces = config->next_interface_id; in config_buf()
188 c->bConfigurationValue = config->bConfigurationValue; in config_buf()
189 c->iConfiguration = config->iConfiguration; in config_buf()
190 c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes; in config_buf()
191 c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2); in config_buf()
194 if (config->descriptors) { in config_buf()
196 config->descriptors); in config_buf()
199 len -= status; in config_buf()
204 list_for_each_entry(f, &config->functions, list) { in config_buf()
207 descriptors = f->ss_descriptors; in config_buf()
210 descriptors = f->hs_descriptors; in config_buf()
213 descriptors = f->descriptors; in config_buf()
222 len -= status; in config_buf()
226 len = next - buf; in config_buf()
227 c->wTotalLength = cpu_to_le16(len); in config_buf()
234 struct usb_gadget *gadget = cdev->gadget; in config_desc()
239 if (gadget->speed == USB_SPEED_SUPER) in config_desc()
240 speed = gadget->speed; in config_desc()
242 if (gadget->speed == USB_SPEED_HIGH) in config_desc()
251 list_for_each_entry(c, &cdev->configs, list) { in config_desc()
254 if (!c->superspeed) in config_desc()
258 if (!c->highspeed) in config_desc()
262 if (!c->fullspeed) in config_desc()
267 return config_buf(c, speed, cdev->req->buf, type); in config_desc()
268 w_value--; in config_desc()
270 return -EINVAL; in config_desc()
275 struct usb_gadget *gadget = cdev->gadget; in count_configs()
281 if (gadget->speed == USB_SPEED_HIGH) in count_configs()
286 list_for_each_entry(c, &cdev->configs, list) { in count_configs()
289 if (!c->highspeed) in count_configs()
292 if (!c->fullspeed) in count_configs()
302 struct usb_qualifier_descriptor *qual = cdev->req->buf; in device_qual()
304 qual->bLength = sizeof(*qual); in device_qual()
305 qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER; in device_qual()
307 qual->bcdUSB = cdev->desc.bcdUSB; in device_qual()
308 qual->bDeviceClass = cdev->desc.bDeviceClass; in device_qual()
309 qual->bDeviceSubClass = cdev->desc.bDeviceSubClass; in device_qual()
310 qual->bDeviceProtocol = cdev->desc.bDeviceProtocol; in device_qual()
312 qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket; in device_qual()
313 qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER); in device_qual()
314 qual->bRESERVED = 0; in device_qual()
323 list_for_each_entry(f, &cdev->config->functions, list) { in reset_config()
324 if (f->disable) in reset_config()
325 f->disable(f); in reset_config()
327 bitmap_zero(f->endpoints, 32); in reset_config()
329 cdev->config = NULL; in reset_config()
335 struct usb_gadget *gadget = cdev->gadget; in set_config()
338 int result = -EINVAL; in set_config()
345 if (cdev->config) in set_config()
349 list_for_each_entry(c, &cdev->configs, list) { in set_config()
350 if (c->bConfigurationValue == number) { in set_config()
362 switch (gadget->speed) { in set_config()
380 }), number, c ? c->label : "unconfigured"); in set_config()
385 cdev->config = c; in set_config()
389 f = c->interface[tmp]; in set_config()
399 switch (gadget->speed) { in set_config()
401 descriptors = f->ss_descriptors; in set_config()
404 descriptors = f->hs_descriptors; in set_config()
407 descriptors = f->descriptors; in set_config()
411 if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT) in set_config()
415 addr = ((ep->bEndpointAddress & 0x80) >> 3) in set_config()
416 | (ep->bEndpointAddress & 0x0f); in set_config()
417 generic_set_bit(addr, f->endpoints); in set_config()
420 result = f->set_alt(f, tmp, 0); in set_config()
422 debug("interface %d (%s/%p) alt 0 --> %d\n", in set_config()
423 tmp, f->name, f, result); in set_config()
431 power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW; in set_config()
438 * usb_add_config() - add a configuration to a device.
443 * One of the main tasks of a composite driver's bind() routine is to
448 * assigns global resources including string IDs, and per-configuration
454 int status = -EINVAL; in usb_add_config()
460 config->bConfigurationValue, in usb_add_config()
461 config->label, config); in usb_add_config()
463 if (!config->bConfigurationValue || !config->bind) in usb_add_config()
467 list_for_each_entry(c, &cdev->configs, list) { in usb_add_config()
468 if (c->bConfigurationValue == config->bConfigurationValue) { in usb_add_config()
469 status = -EBUSY; in usb_add_config()
474 config->cdev = cdev; in usb_add_config()
475 list_add_tail(&config->list, &cdev->configs); in usb_add_config()
477 INIT_LIST_HEAD(&config->functions); in usb_add_config()
478 config->next_interface_id = 0; in usb_add_config()
480 status = config->bind(config); in usb_add_config()
482 list_del(&config->list); in usb_add_config()
483 config->cdev = NULL; in usb_add_config()
486 config->bConfigurationValue, config, in usb_add_config()
487 config->superspeed ? " super" : "", in usb_add_config()
488 config->highspeed ? " high" : "", in usb_add_config()
489 config->fullspeed ? in usb_add_config()
490 (gadget_is_dualspeed(cdev->gadget) ? in usb_add_config()
494 f = config->interface[i]; in usb_add_config()
498 __func__, i, f->name, f); in usb_add_config()
502 usb_ep_autoconfig_reset(cdev->gadget); in usb_add_config()
506 debug("added config '%s'/%u --> %d\n", config->label, in usb_add_config()
507 config->bConfigurationValue, status); in usb_add_config()
512 * We support strings in multiple languages ... string descriptor zero
527 language = cpu_to_le16(s->language); in collect_langs()
528 for (tmp = buf; tmp->val && tmp < end; tmp++) { in collect_langs()
529 if (tmp->val == language) in collect_langs()
532 tmp->val = language; in collect_langs()
550 if (s->language != language) in lookup_string()
556 return -EINVAL; in lookup_string()
577 s->bDescriptorType = USB_DT_STRING; in get_string()
579 sp = composite->strings; in get_string()
581 collect_langs(sp, s->wData); in get_string()
583 list_for_each_entry(c, &cdev->configs, list) { in get_string()
584 sp = c->strings; in get_string()
586 collect_langs(sp, s->wData); in get_string()
588 list_for_each_entry(f, &c->functions, list) { in get_string()
589 sp = f->strings; in get_string()
591 collect_langs(sp, s->wData); in get_string()
595 for (len = 0; len <= 126 && s->wData[len]; len++) in get_string()
598 return -EINVAL; in get_string()
600 s->bLength = 2 * (len + 1); in get_string()
601 return s->bLength; in get_string()
606 * are device-scoped, so we look up each string table we're told in get_string()
607 * about. These lookups are infrequent; simpler-is-better here. in get_string()
609 if (composite->strings) { in get_string()
610 len = lookup_string(composite->strings, buf, language, id); in get_string()
614 list_for_each_entry(c, &cdev->configs, list) { in get_string()
615 if (c->strings) { in get_string()
616 len = lookup_string(c->strings, buf, language, id); in get_string()
620 list_for_each_entry(f, &c->functions, list) { in get_string()
621 if (!f->strings) in get_string()
623 len = lookup_string(f->strings, buf, language, id); in get_string()
628 return -EINVAL; in get_string()
632 * usb_string_id() - allocate an unused string ID
638 * then store that ID in the appropriate descriptors and string table.
647 if (cdev->next_string_id < 254) { in usb_string_id()
651 * 255 reserved as well? -- mina86 in usb_string_id()
653 cdev->next_string_id++; in usb_string_id()
654 return cdev->next_string_id; in usb_string_id()
656 return -ENODEV; in usb_string_id()
660 * usb_string_ids() - allocate unused string IDs in batch
677 u8 next = cdev->next_string_id; in usb_string_ids_tab()
679 for (; str->s; ++str) { in usb_string_ids_tab()
681 return -ENODEV; in usb_string_ids_tab()
682 str->id = ++next; in usb_string_ids_tab()
685 cdev->next_string_id = next; in usb_string_ids_tab()
691 * usb_string_ids_n() - allocate unused string IDs in batch
696 * Returns the first requested ID. This ID and next @n-1 IDs are now
697 * valid IDs. At least provided that @n is non-zero because if it
702 * then store that ID in the appropriate descriptors and string table.
711 u8 next = c->next_string_id; in usb_string_ids_n()
714 return -ENODEV; in usb_string_ids_n()
716 c->next_string_id += n; in usb_string_ids_n()
722 if (req->status || req->actual != req->length) in composite_setup_complete()
723 debug("%s: setup complete --> %d, %d/%d\n", __func__, in composite_setup_complete()
724 req->status, req->actual, req->length); in composite_setup_complete()
732 struct usb_bos_descriptor *bos = cdev->req->buf; in bos_desc()
734 bos->bLength = USB_DT_BOS_SIZE; in bos_desc()
735 bos->bDescriptorType = USB_DT_BOS; in bos_desc()
736 bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE); in bos_desc()
737 bos->bNumDeviceCaps = 0; in bos_desc()
739 if (cdev->gadget->speed < USB_SPEED_SUPER) { in bos_desc()
741 cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); in bos_desc()
742 bos->bNumDeviceCaps++; in bos_desc()
743 bos->wTotalLength = cpu_to_le16(bos->wTotalLength + in bos_desc()
745 cap->bLength = sizeof(*cap); in bos_desc()
746 cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; in bos_desc()
747 cap->bDevCapabilityType = 0; in bos_desc()
752 * operating in USB2.0 HS mode. in bos_desc()
754 usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength); in bos_desc()
755 bos->bNumDeviceCaps++; in bos_desc()
756 le16_add_cpu_packed((__le16_packed *)&bos->wTotalLength, in bos_desc()
758 usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; in bos_desc()
759 usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; in bos_desc()
760 usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; in bos_desc()
761 usb_ext->bmAttributes = USB_LPM_SUPPORT; in bos_desc()
767 ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); in bos_desc()
768 bos->bNumDeviceCaps++; in bos_desc()
769 le16_add_cpu_packed((__le16_packed *)&bos->wTotalLength, in bos_desc()
771 ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE; in bos_desc()
772 ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; in bos_desc()
773 ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE; in bos_desc()
774 ss_cap->bmAttributes = 0; /* LTM is not supported yet */ in bos_desc()
775 ss_cap->wSpeedSupported = cpu_to_le16(USB_FULL_SPEED_OPERATION | in bos_desc()
778 ss_cap->bFunctionalitySupport = USB_FULL_SPEED_OPERATION; in bos_desc()
779 ss_cap->bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT; in bos_desc()
780 ss_cap->bU2DevExitLat = cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); in bos_desc()
783 return le16_to_cpu(bos->wTotalLength); in bos_desc()
788 * not handled lower down, in hardware or the hardware driver(like
791 * the work is in config and function specific setup.
796 u16 w_length = le16_to_cpu(ctrl->wLength); in composite_setup()
797 u16 w_index = le16_to_cpu(ctrl->wIndex); in composite_setup()
798 u16 w_value = le16_to_cpu(ctrl->wValue); in composite_setup()
801 int value = -EOPNOTSUPP; in composite_setup()
802 struct usb_request *req = cdev->req; in composite_setup()
809 * partial re-init of the response message; the function or the in composite_setup()
810 * gadget might need to intercept e.g. a control-OUT completion in composite_setup()
813 req->zero = 0; in composite_setup()
814 req->complete = composite_setup_complete; in composite_setup()
815 req->length = USB_BUFSIZ; in composite_setup()
816 gadget->ep0->driver_data = cdev; in composite_setup()
817 standard = (ctrl->bRequestType & USB_TYPE_MASK) in composite_setup()
823 switch (ctrl->bRequest) { in composite_setup()
827 if (ctrl->bRequestType != USB_DIR_IN) in composite_setup()
832 cdev->desc.bNumConfigurations = in composite_setup()
836 gadget->speed >= USB_SPEED_SUPER) { in composite_setup()
841 if (!strncmp(cdev->driver->name, in composite_setup()
843 cdev->desc.bcdUSB = cpu_to_le16(0x0301); in composite_setup()
845 cdev->desc.bcdUSB = cpu_to_le16(0x0300); in composite_setup()
846 cdev->desc.bMaxPacketSize0 = 9; in composite_setup()
848 cdev->desc.bMaxPacketSize0 = in composite_setup()
849 cdev->gadget->ep0->maxpacket; in composite_setup()
852 value = min(w_length, (u16) sizeof cdev->desc); in composite_setup()
853 memcpy(req->buf, &cdev->desc, value); in composite_setup()
872 value = get_string(cdev, req->buf, in composite_setup()
882 * which request BOS descriptor in this case that bcdUSB in composite_setup()
886 !strncmp(cdev->driver->name, "rkusb_ums_dnl", 13)) { in composite_setup()
905 if (ctrl->bRequestType != 0) in composite_setup()
908 if (gadget->a_hnp_support) in composite_setup()
910 else if (gadget->a_alt_hnp_support) in composite_setup()
919 if (ctrl->bRequestType != USB_DIR_IN) in composite_setup()
921 if (cdev->config) in composite_setup()
922 *(u8 *)req->buf = cdev->config->bConfigurationValue; in composite_setup()
924 *(u8 *)req->buf = 0; in composite_setup()
933 if (ctrl->bRequestType != USB_RECIP_INTERFACE) in composite_setup()
935 if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) in composite_setup()
937 f = cdev->config->interface[intf]; in composite_setup()
940 if (w_value && !f->set_alt) in composite_setup()
942 value = f->set_alt(f, w_index, w_value); in composite_setup()
945 if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) in composite_setup()
947 if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) in composite_setup()
949 f = cdev->config->interface[intf]; in composite_setup()
953 value = f->get_alt ? f->get_alt(f, w_index) : 0; in composite_setup()
956 *((u8 *)req->buf) = value; in composite_setup()
961 debug("non-core control req%02x.%02x v%04x i%04x l%d\n", in composite_setup()
962 ctrl->bRequestType, ctrl->bRequest, in composite_setup()
965 if (!cdev->config) in composite_setup()
973 switch (ctrl->bRequestType & USB_RECIP_MASK) { in composite_setup()
975 if (!cdev->config) in composite_setup()
977 f = cdev->config->interface[intf]; in composite_setup()
981 if (!cdev->config) in composite_setup()
984 list_for_each_entry(f, &cdev->config->functions, list) { in composite_setup()
985 if (test_bit(endp, f->endpoints)) in composite_setup()
988 if (&f->list == &cdev->config->functions) in composite_setup()
992 * dfu-util (version 0.5) sets bmRequestType.Receipent = Device in composite_setup()
993 * for non-standard request (w_value = 0x21, in composite_setup()
994 * bRequest = GET_DESCRIPTOR in this case). in composite_setup()
999 * In the below code it is checked if only one interface is in composite_setup()
1001 * function's setup (f->setup) is called to handle this in composite_setup()
1002 * special non-standard request. in composite_setup()
1005 if (cdev->config) { in composite_setup()
1006 debug("cdev->config->next_interface_id: %d intf: %d\n", in composite_setup()
1007 cdev->config->next_interface_id, intf); in composite_setup()
1008 if (cdev->config->next_interface_id == 1) in composite_setup()
1009 f = cdev->config->interface[intf]; in composite_setup()
1014 if (f && f->setup) in composite_setup()
1015 value = f->setup(f, ctrl); in composite_setup()
1017 c = cdev->config; in composite_setup()
1018 if (c->setup) in composite_setup()
1019 value = c->setup(c, ctrl); in composite_setup()
1027 req->length = value; in composite_setup()
1028 req->zero = value < w_length; in composite_setup()
1029 value = usb_ep_queue(gadget->ep0, req, GFP_KERNEL); in composite_setup()
1031 debug("ep_queue --> %d\n", value); in composite_setup()
1032 req->status = 0; in composite_setup()
1033 composite_setup_complete(gadget->ep0, req); in composite_setup()
1046 if (cdev->config) in composite_disconnect()
1048 if (composite->disconnect) in composite_disconnect()
1049 composite->disconnect(cdev); in composite_disconnect()
1062 * state protected by cdev->lock. in composite_unbind()
1064 BUG_ON(cdev->config); in composite_unbind()
1066 while (!list_empty(&cdev->configs)) { in composite_unbind()
1067 c = list_first_entry(&cdev->configs, in composite_unbind()
1069 while (!list_empty(&c->functions)) { in composite_unbind()
1070 f = list_first_entry(&c->functions, in composite_unbind()
1072 list_del(&f->list); in composite_unbind()
1073 if (f->unbind) { in composite_unbind()
1075 f->name, f); in composite_unbind()
1076 f->unbind(c, f); in composite_unbind()
1079 list_del(&c->list); in composite_unbind()
1080 if (c->unbind) { in composite_unbind()
1081 debug("unbind config '%s'/%p\n", c->label, c); in composite_unbind()
1082 c->unbind(c); in composite_unbind()
1086 if (composite->unbind) in composite_unbind()
1087 composite->unbind(cdev); in composite_unbind()
1089 if (cdev->req) { in composite_unbind()
1090 kfree(cdev->req->buf); in composite_unbind()
1091 usb_ep_free_request(gadget->ep0, cdev->req); in composite_unbind()
1096 composite = NULL; in composite_unbind()
1101 int status = -ENOMEM; in composite_bind()
1108 cdev->gadget = gadget; in composite_bind()
1110 INIT_LIST_HEAD(&cdev->configs); in composite_bind()
1113 cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); in composite_bind()
1114 if (!cdev->req) in composite_bind()
1116 cdev->req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, USB_BUFSIZ); in composite_bind()
1117 if (!cdev->req->buf) in composite_bind()
1119 cdev->req->complete = composite_setup_complete; in composite_bind()
1120 gadget->ep0->driver_data = cdev; in composite_bind()
1122 cdev->bufsiz = USB_BUFSIZ; in composite_bind()
1123 cdev->driver = composite; in composite_bind()
1126 usb_ep_autoconfig_reset(cdev->gadget); in composite_bind()
1128 status = composite->bind(cdev); in composite_bind()
1132 memcpy(&cdev->desc, composite->dev, in composite_bind()
1134 cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; in composite_bind()
1136 debug("%s: ready\n", composite->name); in composite_bind()
1151 if (cdev->config) { in composite_suspend()
1152 list_for_each_entry(f, &cdev->config->functions, list) { in composite_suspend()
1153 if (f->suspend) in composite_suspend()
1154 f->suspend(f); in composite_suspend()
1157 if (composite->suspend) in composite_suspend()
1158 composite->suspend(cdev); in composite_suspend()
1160 cdev->suspended = 1; in composite_suspend()
1170 if (composite->resume) in composite_resume()
1171 composite->resume(cdev); in composite_resume()
1172 if (cdev->config) { in composite_resume()
1173 list_for_each_entry(f, &cdev->config->functions, list) { in composite_resume()
1174 if (f->resume) in composite_resume()
1175 f->resume(f); in composite_resume()
1179 cdev->suspended = 0; in composite_resume()
1197 * usb_composite_register() - register a composite driver
1201 * This function is used to register drivers using the composite driver
1208 * while it was binding. That would usually be done in order to wait for
1215 if (!driver || !driver->dev || !driver->bind || composite) in usb_composite_register()
1216 return -EINVAL; in usb_composite_register()
1218 if (!driver->name) in usb_composite_register()
1219 driver->name = "composite"; in usb_composite_register()
1220 composite = driver; in usb_composite_register()
1224 composite = NULL; in usb_composite_register()
1230 * usb_composite_unregister() - unregister a composite driver
1233 * This function is used to unregister drivers using the composite
1238 if (composite != driver) in usb_composite_unregister()
1241 composite = NULL; in usb_composite_unregister()