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