15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+ 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 2004 David Brownell 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 81da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 91da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 101da177e4SLinus Torvalds * (at your option) any later version. 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds #include <linux/kernel.h> 14dc995fc2SSebastian Andrzej Siewior #include <linux/module.h> 151da177e4SLinus Torvalds #include <linux/types.h> 161da177e4SLinus Torvalds #include <linux/device.h> 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds #include <linux/ctype.h> 191da177e4SLinus Torvalds #include <linux/string.h> 201da177e4SLinus Torvalds 215f848137SDavid Brownell #include <linux/usb/ch9.h> 229454a57aSDavid Brownell #include <linux/usb/gadget.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds /** 25a59d6b91STatyana Brokhman * usb_ep_autoconfig_ss() - choose an endpoint matching the ep 26a59d6b91STatyana Brokhman * descriptor and ep companion descriptor 27a59d6b91STatyana Brokhman * @gadget: The device to which the endpoint must belong. 28a59d6b91STatyana Brokhman * @desc: Endpoint descriptor, with endpoint direction and transfer mode 29a59d6b91STatyana Brokhman * initialized. For periodic transfers, the maximum packet 30a59d6b91STatyana Brokhman * size must also be initialized. This is modified on 31a59d6b91STatyana Brokhman * success. 32a59d6b91STatyana Brokhman * @ep_comp: Endpoint companion descriptor, with the required 33a59d6b91STatyana Brokhman * number of streams. Will be modified when the chosen EP 34a59d6b91STatyana Brokhman * supports a different number of streams. 35a59d6b91STatyana Brokhman * 36a59d6b91STatyana Brokhman * This routine replaces the usb_ep_autoconfig when needed 37a59d6b91STatyana Brokhman * superspeed enhancments. If such enhancemnets are required, 38a59d6b91STatyana Brokhman * the FD should call usb_ep_autoconfig_ss directly and provide 39a59d6b91STatyana Brokhman * the additional ep_comp parameter. 40a59d6b91STatyana Brokhman * 41a59d6b91STatyana Brokhman * By choosing an endpoint to use with the specified descriptor, 42a59d6b91STatyana Brokhman * this routine simplifies writing gadget drivers that work with 43a59d6b91STatyana Brokhman * multiple USB device controllers. The endpoint would be 44a59d6b91STatyana Brokhman * passed later to usb_ep_enable(), along with some descriptor. 45a59d6b91STatyana Brokhman * 46a59d6b91STatyana Brokhman * That second descriptor won't always be the same as the first one. 47a59d6b91STatyana Brokhman * For example, isochronous endpoints can be autoconfigured for high 48a59d6b91STatyana Brokhman * bandwidth, and then used in several lower bandwidth altsettings. 49a59d6b91STatyana Brokhman * Also, high and full speed descriptors will be different. 50a59d6b91STatyana Brokhman * 51a59d6b91STatyana Brokhman * Be sure to examine and test the results of autoconfiguration 52a59d6b91STatyana Brokhman * on your hardware. This code may not make the best choices 53a59d6b91STatyana Brokhman * about how to use the USB controller, and it can't know all 54a59d6b91STatyana Brokhman * the restrictions that may apply. Some combinations of driver 55a59d6b91STatyana Brokhman * and hardware won't be able to autoconfigure. 56a59d6b91STatyana Brokhman * 57f871cb9bSRobert Baldyga * On success, this returns an claimed usb_ep, and modifies the endpoint 58a59d6b91STatyana Brokhman * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value 59a59d6b91STatyana Brokhman * is initialized as if the endpoint were used at full speed and 60a59d6b91STatyana Brokhman * the bmAttribute field in the ep companion descriptor is 61a59d6b91STatyana Brokhman * updated with the assigned number of streams if it is 62a59d6b91STatyana Brokhman * different from the original value. To prevent the endpoint 63f871cb9bSRobert Baldyga * from being returned by a later autoconfig call, claims it by 64cc476b42SRobert Baldyga * assigning ep->claimed to true. 65a59d6b91STatyana Brokhman * 66a59d6b91STatyana Brokhman * On failure, this returns a null endpoint descriptor. 67a59d6b91STatyana Brokhman */ 68a59d6b91STatyana Brokhman struct usb_ep *usb_ep_autoconfig_ss( 69a59d6b91STatyana Brokhman struct usb_gadget *gadget, 70a59d6b91STatyana Brokhman struct usb_endpoint_descriptor *desc, 71a59d6b91STatyana Brokhman struct usb_ss_ep_comp_descriptor *ep_comp 72a59d6b91STatyana Brokhman ) 73a59d6b91STatyana Brokhman { 74a59d6b91STatyana Brokhman struct usb_ep *ep; 75a59d6b91STatyana Brokhman u8 type; 76a59d6b91STatyana Brokhman 77a59d6b91STatyana Brokhman type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 78a59d6b91STatyana Brokhman 79596c154dSRobert Baldyga if (gadget->ops->match_ep) { 80596c154dSRobert Baldyga ep = gadget->ops->match_ep(gadget, desc, ep_comp); 81596c154dSRobert Baldyga if (ep) 82596c154dSRobert Baldyga goto found_ep; 83596c154dSRobert Baldyga } 84596c154dSRobert Baldyga 85a59d6b91STatyana Brokhman /* Second, look at endpoints until an unclaimed one looks usable */ 86a59d6b91STatyana Brokhman list_for_each_entry (ep, &gadget->ep_list, ep_list) { 874278c687SRobert Baldyga if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) 88609ca228SSebastian Andrzej Siewior goto found_ep; 89a59d6b91STatyana Brokhman } 90a59d6b91STatyana Brokhman 91a59d6b91STatyana Brokhman /* Fail */ 92a59d6b91STatyana Brokhman return NULL; 93609ca228SSebastian Andrzej Siewior found_ep: 945dbe135aSRobert Baldyga 955dbe135aSRobert Baldyga /* 965dbe135aSRobert Baldyga * If the protocol driver hasn't yet decided on wMaxPacketSize 975dbe135aSRobert Baldyga * and wants to know the maximum possible, provide the info. 985dbe135aSRobert Baldyga */ 995dbe135aSRobert Baldyga if (desc->wMaxPacketSize == 0) 1005dbe135aSRobert Baldyga desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit); 1015dbe135aSRobert Baldyga 1025dbe135aSRobert Baldyga /* report address */ 1035dbe135aSRobert Baldyga desc->bEndpointAddress &= USB_DIR_IN; 1045dbe135aSRobert Baldyga if (isdigit(ep->name[2])) { 1055dbe135aSRobert Baldyga u8 num = simple_strtoul(&ep->name[2], NULL, 10); 1065dbe135aSRobert Baldyga desc->bEndpointAddress |= num; 1075dbe135aSRobert Baldyga } else if (desc->bEndpointAddress & USB_DIR_IN) { 1085dbe135aSRobert Baldyga if (++gadget->in_epnum > 15) 1095dbe135aSRobert Baldyga return NULL; 1105dbe135aSRobert Baldyga desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum; 1115dbe135aSRobert Baldyga } else { 1125dbe135aSRobert Baldyga if (++gadget->out_epnum > 15) 1135dbe135aSRobert Baldyga return NULL; 1145dbe135aSRobert Baldyga desc->bEndpointAddress |= gadget->out_epnum; 1155dbe135aSRobert Baldyga } 1165dbe135aSRobert Baldyga 1175dbe135aSRobert Baldyga /* report (variable) full speed bulk maxpacket */ 1185dbe135aSRobert Baldyga if ((type == USB_ENDPOINT_XFER_BULK) && !ep_comp) { 1195dbe135aSRobert Baldyga int size = ep->maxpacket_limit; 1205dbe135aSRobert Baldyga 1215dbe135aSRobert Baldyga /* min() doesn't work on bitfields with gcc-3.5 */ 1225dbe135aSRobert Baldyga if (size > 64) 1235dbe135aSRobert Baldyga size = 64; 1245dbe135aSRobert Baldyga desc->wMaxPacketSize = cpu_to_le16(size); 1255dbe135aSRobert Baldyga } 1265dbe135aSRobert Baldyga 1275dbe135aSRobert Baldyga ep->address = desc->bEndpointAddress; 128609ca228SSebastian Andrzej Siewior ep->desc = NULL; 129609ca228SSebastian Andrzej Siewior ep->comp_desc = NULL; 130cc476b42SRobert Baldyga ep->claimed = true; 131609ca228SSebastian Andrzej Siewior return ep; 132a59d6b91STatyana Brokhman } 133dc995fc2SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss); 134a59d6b91STatyana Brokhman 135a59d6b91STatyana Brokhman /** 136a59d6b91STatyana Brokhman * usb_ep_autoconfig() - choose an endpoint matching the 137a59d6b91STatyana Brokhman * descriptor 1381da177e4SLinus Torvalds * @gadget: The device to which the endpoint must belong. 1391da177e4SLinus Torvalds * @desc: Endpoint descriptor, with endpoint direction and transfer mode 1401da177e4SLinus Torvalds * initialized. For periodic transfers, the maximum packet 1411da177e4SLinus Torvalds * size must also be initialized. This is modified on success. 1421da177e4SLinus Torvalds * 1431da177e4SLinus Torvalds * By choosing an endpoint to use with the specified descriptor, this 1441da177e4SLinus Torvalds * routine simplifies writing gadget drivers that work with multiple 1451da177e4SLinus Torvalds * USB device controllers. The endpoint would be passed later to 1461da177e4SLinus Torvalds * usb_ep_enable(), along with some descriptor. 1471da177e4SLinus Torvalds * 1481da177e4SLinus Torvalds * That second descriptor won't always be the same as the first one. 1491da177e4SLinus Torvalds * For example, isochronous endpoints can be autoconfigured for high 1501da177e4SLinus Torvalds * bandwidth, and then used in several lower bandwidth altsettings. 1511da177e4SLinus Torvalds * Also, high and full speed descriptors will be different. 1521da177e4SLinus Torvalds * 1531da177e4SLinus Torvalds * Be sure to examine and test the results of autoconfiguration on your 1541da177e4SLinus Torvalds * hardware. This code may not make the best choices about how to use the 1551da177e4SLinus Torvalds * USB controller, and it can't know all the restrictions that may apply. 1561da177e4SLinus Torvalds * Some combinations of driver and hardware won't be able to autoconfigure. 1571da177e4SLinus Torvalds * 158f871cb9bSRobert Baldyga * On success, this returns an claimed usb_ep, and modifies the endpoint 1591da177e4SLinus Torvalds * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value 1601da177e4SLinus Torvalds * is initialized as if the endpoint were used at full speed. To prevent 161f871cb9bSRobert Baldyga * the endpoint from being returned by a later autoconfig call, claims it 162cc476b42SRobert Baldyga * by assigning ep->claimed to true. 1631da177e4SLinus Torvalds * 1641da177e4SLinus Torvalds * On failure, this returns a null endpoint descriptor. 1651da177e4SLinus Torvalds */ 16628824b18SMichal Nazarewicz struct usb_ep *usb_ep_autoconfig( 1671da177e4SLinus Torvalds struct usb_gadget *gadget, 1681da177e4SLinus Torvalds struct usb_endpoint_descriptor *desc 1691da177e4SLinus Torvalds ) 1701da177e4SLinus Torvalds { 171a59d6b91STatyana Brokhman return usb_ep_autoconfig_ss(gadget, desc, NULL); 1721da177e4SLinus Torvalds } 173dc995fc2SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_ep_autoconfig); 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds /** 176b67f628cSRobert Baldyga * usb_ep_autoconfig_release - releases endpoint and set it to initial state 177b67f628cSRobert Baldyga * @ep: endpoint which should be released 178b67f628cSRobert Baldyga * 179b67f628cSRobert Baldyga * This function can be used during function bind for endpoints obtained 180b67f628cSRobert Baldyga * from usb_ep_autoconfig(). It unclaims endpoint claimed by 181b67f628cSRobert Baldyga * usb_ep_autoconfig() to make it available for other functions. Endpoint 182b67f628cSRobert Baldyga * which was released is no longer invalid and shouldn't be used in 183b67f628cSRobert Baldyga * context of function which released it. 184b67f628cSRobert Baldyga */ 185b67f628cSRobert Baldyga void usb_ep_autoconfig_release(struct usb_ep *ep) 186b67f628cSRobert Baldyga { 187b67f628cSRobert Baldyga ep->claimed = false; 188b67f628cSRobert Baldyga ep->driver_data = NULL; 189b67f628cSRobert Baldyga } 190b67f628cSRobert Baldyga EXPORT_SYMBOL_GPL(usb_ep_autoconfig_release); 191b67f628cSRobert Baldyga 192b67f628cSRobert Baldyga /** 1931da177e4SLinus Torvalds * usb_ep_autoconfig_reset - reset endpoint autoconfig state 1941da177e4SLinus Torvalds * @gadget: device for which autoconfig state will be reset 1951da177e4SLinus Torvalds * 1961da177e4SLinus Torvalds * Use this for devices where one configuration may need to assign 1971da177e4SLinus Torvalds * endpoint resources very differently from the next one. It clears 198cc476b42SRobert Baldyga * state such as ep->claimed and the record of assigned endpoints 1991da177e4SLinus Torvalds * used by usb_ep_autoconfig(). 2001da177e4SLinus Torvalds */ 20128824b18SMichal Nazarewicz void usb_ep_autoconfig_reset (struct usb_gadget *gadget) 2021da177e4SLinus Torvalds { 2031da177e4SLinus Torvalds struct usb_ep *ep; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds list_for_each_entry (ep, &gadget->ep_list, ep_list) { 206cc476b42SRobert Baldyga ep->claimed = false; 207e4c1b1baSRobert Baldyga ep->driver_data = NULL; 2081da177e4SLinus Torvalds } 209e87bb711SSebastian Andrzej Siewior gadget->in_epnum = 0; 210e87bb711SSebastian Andrzej Siewior gadget->out_epnum = 0; 2111da177e4SLinus Torvalds } 212dc995fc2SSebastian Andrzej Siewior EXPORT_SYMBOL_GPL(usb_ep_autoconfig_reset); 213