123cd1385SRemy Bohmer /* 223cd1385SRemy Bohmer * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers 323cd1385SRemy Bohmer * 423cd1385SRemy Bohmer * Copyright (C) 2004 David Brownell 523cd1385SRemy Bohmer * 61a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 723cd1385SRemy Bohmer * 81a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 923cd1385SRemy Bohmer * 10a187559eSBin Meng * Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and 1123cd1385SRemy Bohmer * Remy Bohmer <linux@bohmer.net> 1223cd1385SRemy Bohmer */ 1323cd1385SRemy Bohmer 1423cd1385SRemy Bohmer #include <common.h> 1523cd1385SRemy Bohmer #include <linux/usb/ch9.h> 161221ce45SMasahiro Yamada #include <linux/errno.h> 1723cd1385SRemy Bohmer #include <linux/usb/gadget.h> 18b2fb47f1STom Rini #include <asm/unaligned.h> 1923cd1385SRemy Bohmer #include "gadget_chips.h" 2023cd1385SRemy Bohmer 2123cd1385SRemy Bohmer #define isdigit(c) ('0' <= (c) && (c) <= '9') 2223cd1385SRemy Bohmer 2323cd1385SRemy Bohmer /* we must assign addresses for configurable endpoints (like net2280) */ 2423cd1385SRemy Bohmer static unsigned epnum; 2523cd1385SRemy Bohmer 266142e0aeSVitaly Kuzmichev /* #define MANY_ENDPOINTS */ 2723cd1385SRemy Bohmer #ifdef MANY_ENDPOINTS 2823cd1385SRemy Bohmer /* more than 15 configurable endpoints */ 2923cd1385SRemy Bohmer static unsigned in_epnum; 3023cd1385SRemy Bohmer #endif 3123cd1385SRemy Bohmer 3223cd1385SRemy Bohmer 3323cd1385SRemy Bohmer /* 3423cd1385SRemy Bohmer * This should work with endpoints from controller drivers sharing the 3523cd1385SRemy Bohmer * same endpoint naming convention. By example: 3623cd1385SRemy Bohmer * 3723cd1385SRemy Bohmer * - ep1, ep2, ... address is fixed, not direction or type 3823cd1385SRemy Bohmer * - ep1in, ep2out, ... address and direction are fixed, not type 3923cd1385SRemy Bohmer * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction 4023cd1385SRemy Bohmer * - ep1in-bulk, ep2out-iso, ... all three are fixed 4123cd1385SRemy Bohmer * - ep-* ... no functionality restrictions 4223cd1385SRemy Bohmer * 4323cd1385SRemy Bohmer * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal. 4423cd1385SRemy Bohmer * Less common restrictions are implied by gadget_is_*(). 4523cd1385SRemy Bohmer * 4623cd1385SRemy Bohmer * NOTE: each endpoint is unidirectional, as specified by its USB 4723cd1385SRemy Bohmer * descriptor; and isn't specific to a configuration or altsetting. 4823cd1385SRemy Bohmer */ 496142e0aeSVitaly Kuzmichev static int ep_matches( 5023cd1385SRemy Bohmer struct usb_gadget *gadget, 5123cd1385SRemy Bohmer struct usb_ep *ep, 5223cd1385SRemy Bohmer struct usb_endpoint_descriptor *desc 5323cd1385SRemy Bohmer ) 5423cd1385SRemy Bohmer { 5523cd1385SRemy Bohmer u8 type; 5623cd1385SRemy Bohmer const char *tmp; 5723cd1385SRemy Bohmer u16 max; 5823cd1385SRemy Bohmer 5923cd1385SRemy Bohmer /* endpoint already claimed? */ 6023cd1385SRemy Bohmer if (NULL != ep->driver_data) 6123cd1385SRemy Bohmer return 0; 6223cd1385SRemy Bohmer 6323cd1385SRemy Bohmer /* only support ep0 for portable CONTROL traffic */ 6423cd1385SRemy Bohmer type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 6523cd1385SRemy Bohmer if (USB_ENDPOINT_XFER_CONTROL == type) 6623cd1385SRemy Bohmer return 0; 6723cd1385SRemy Bohmer 6823cd1385SRemy Bohmer /* some other naming convention */ 6923cd1385SRemy Bohmer if ('e' != ep->name[0]) 7023cd1385SRemy Bohmer return 0; 7123cd1385SRemy Bohmer 7223cd1385SRemy Bohmer /* type-restriction: "-iso", "-bulk", or "-int". 7323cd1385SRemy Bohmer * direction-restriction: "in", "out". 7423cd1385SRemy Bohmer */ 7523cd1385SRemy Bohmer if ('-' != ep->name[2]) { 7623cd1385SRemy Bohmer tmp = strrchr(ep->name, '-'); 7723cd1385SRemy Bohmer if (tmp) { 7823cd1385SRemy Bohmer switch (type) { 7923cd1385SRemy Bohmer case USB_ENDPOINT_XFER_INT: 8023cd1385SRemy Bohmer /* bulk endpoints handle interrupt transfers, 8123cd1385SRemy Bohmer * except the toggle-quirky iso-synch kind 8223cd1385SRemy Bohmer */ 836142e0aeSVitaly Kuzmichev if ('s' == tmp[2]) /* == "-iso" */ 8423cd1385SRemy Bohmer return 0; 8523cd1385SRemy Bohmer /* for now, avoid PXA "interrupt-in"; 8623cd1385SRemy Bohmer * it's documented as never using DATA1. 8723cd1385SRemy Bohmer */ 8823cd1385SRemy Bohmer if (gadget_is_pxa(gadget) 8923cd1385SRemy Bohmer && 'i' == tmp[1]) 9023cd1385SRemy Bohmer return 0; 9123cd1385SRemy Bohmer break; 9223cd1385SRemy Bohmer case USB_ENDPOINT_XFER_BULK: 936142e0aeSVitaly Kuzmichev if ('b' != tmp[1]) /* != "-bulk" */ 9423cd1385SRemy Bohmer return 0; 9523cd1385SRemy Bohmer break; 9623cd1385SRemy Bohmer case USB_ENDPOINT_XFER_ISOC: 976142e0aeSVitaly Kuzmichev if ('s' != tmp[2]) /* != "-iso" */ 9823cd1385SRemy Bohmer return 0; 9923cd1385SRemy Bohmer } 10023cd1385SRemy Bohmer } else { 10123cd1385SRemy Bohmer tmp = ep->name + strlen(ep->name); 10223cd1385SRemy Bohmer } 10323cd1385SRemy Bohmer 10423cd1385SRemy Bohmer /* direction-restriction: "..in-..", "out-.." */ 10523cd1385SRemy Bohmer tmp--; 10623cd1385SRemy Bohmer if (!isdigit(*tmp)) { 10723cd1385SRemy Bohmer if (desc->bEndpointAddress & USB_DIR_IN) { 10823cd1385SRemy Bohmer if ('n' != *tmp) 10923cd1385SRemy Bohmer return 0; 11023cd1385SRemy Bohmer } else { 11123cd1385SRemy Bohmer if ('t' != *tmp) 11223cd1385SRemy Bohmer return 0; 11323cd1385SRemy Bohmer } 11423cd1385SRemy Bohmer } 11523cd1385SRemy Bohmer } 11623cd1385SRemy Bohmer 11723cd1385SRemy Bohmer /* endpoint maxpacket size is an input parameter, except for bulk 11823cd1385SRemy Bohmer * where it's an output parameter representing the full speed limit. 11923cd1385SRemy Bohmer * the usb spec fixes high speed bulk maxpacket at 512 bytes. 12023cd1385SRemy Bohmer */ 121b2fb47f1STom Rini max = 0x7ff & le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); 12223cd1385SRemy Bohmer switch (type) { 12323cd1385SRemy Bohmer case USB_ENDPOINT_XFER_INT: 12423cd1385SRemy Bohmer /* INT: limit 64 bytes full speed, 1024 high speed */ 12523cd1385SRemy Bohmer if (!gadget->is_dualspeed && max > 64) 12623cd1385SRemy Bohmer return 0; 12723cd1385SRemy Bohmer /* FALLTHROUGH */ 12823cd1385SRemy Bohmer 12923cd1385SRemy Bohmer case USB_ENDPOINT_XFER_ISOC: 13023cd1385SRemy Bohmer /* ISO: limit 1023 bytes full speed, 1024 high speed */ 13123cd1385SRemy Bohmer if (ep->maxpacket < max) 13223cd1385SRemy Bohmer return 0; 13323cd1385SRemy Bohmer if (!gadget->is_dualspeed && max > 1023) 13423cd1385SRemy Bohmer return 0; 13523cd1385SRemy Bohmer 13623cd1385SRemy Bohmer /* BOTH: "high bandwidth" works only at high speed */ 137b2fb47f1STom Rini if ((get_unaligned(&desc->wMaxPacketSize) & 138b2fb47f1STom Rini __constant_cpu_to_le16(3<<11))) { 13923cd1385SRemy Bohmer if (!gadget->is_dualspeed) 14023cd1385SRemy Bohmer return 0; 14123cd1385SRemy Bohmer /* configure your hardware with enough buffering!! */ 14223cd1385SRemy Bohmer } 14323cd1385SRemy Bohmer break; 14423cd1385SRemy Bohmer } 14523cd1385SRemy Bohmer 14623cd1385SRemy Bohmer /* MATCH!! */ 14723cd1385SRemy Bohmer 14823cd1385SRemy Bohmer /* report address */ 14923cd1385SRemy Bohmer if (isdigit(ep->name[2])) { 150c0ef5131SVitaly Kuzmichev u8 num = simple_strtoul(&ep->name[2], NULL, 10); 15123cd1385SRemy Bohmer desc->bEndpointAddress |= num; 15223cd1385SRemy Bohmer #ifdef MANY_ENDPOINTS 15323cd1385SRemy Bohmer } else if (desc->bEndpointAddress & USB_DIR_IN) { 15423cd1385SRemy Bohmer if (++in_epnum > 15) 15523cd1385SRemy Bohmer return 0; 15623cd1385SRemy Bohmer desc->bEndpointAddress = USB_DIR_IN | in_epnum; 15723cd1385SRemy Bohmer #endif 15823cd1385SRemy Bohmer } else { 15923cd1385SRemy Bohmer if (++epnum > 15) 16023cd1385SRemy Bohmer return 0; 16123cd1385SRemy Bohmer desc->bEndpointAddress |= epnum; 16223cd1385SRemy Bohmer } 16323cd1385SRemy Bohmer 16423cd1385SRemy Bohmer /* report (variable) full speed bulk maxpacket */ 16523cd1385SRemy Bohmer if (USB_ENDPOINT_XFER_BULK == type) { 16623cd1385SRemy Bohmer int size = ep->maxpacket; 16723cd1385SRemy Bohmer 16823cd1385SRemy Bohmer /* min() doesn't work on bitfields with gcc-3.5 */ 16923cd1385SRemy Bohmer if (size > 64) 17023cd1385SRemy Bohmer size = 64; 171b2fb47f1STom Rini put_unaligned(cpu_to_le16(size), &desc->wMaxPacketSize); 17223cd1385SRemy Bohmer } 17323cd1385SRemy Bohmer return 1; 17423cd1385SRemy Bohmer } 17523cd1385SRemy Bohmer 17623cd1385SRemy Bohmer static struct usb_ep * 17723cd1385SRemy Bohmer find_ep(struct usb_gadget *gadget, const char *name) 17823cd1385SRemy Bohmer { 17923cd1385SRemy Bohmer struct usb_ep *ep; 18023cd1385SRemy Bohmer 18123cd1385SRemy Bohmer list_for_each_entry(ep, &gadget->ep_list, ep_list) { 18223cd1385SRemy Bohmer if (0 == strcmp(ep->name, name)) 18323cd1385SRemy Bohmer return ep; 18423cd1385SRemy Bohmer } 18523cd1385SRemy Bohmer return NULL; 18623cd1385SRemy Bohmer } 18723cd1385SRemy Bohmer 18823cd1385SRemy Bohmer /** 18923cd1385SRemy Bohmer * usb_ep_autoconfig - choose an endpoint matching the descriptor 19023cd1385SRemy Bohmer * @gadget: The device to which the endpoint must belong. 19123cd1385SRemy Bohmer * @desc: Endpoint descriptor, with endpoint direction and transfer mode 19223cd1385SRemy Bohmer * initialized. For periodic transfers, the maximum packet 19323cd1385SRemy Bohmer * size must also be initialized. This is modified on success. 19423cd1385SRemy Bohmer * 19523cd1385SRemy Bohmer * By choosing an endpoint to use with the specified descriptor, this 19623cd1385SRemy Bohmer * routine simplifies writing gadget drivers that work with multiple 19723cd1385SRemy Bohmer * USB device controllers. The endpoint would be passed later to 19823cd1385SRemy Bohmer * usb_ep_enable(), along with some descriptor. 19923cd1385SRemy Bohmer * 20023cd1385SRemy Bohmer * That second descriptor won't always be the same as the first one. 20123cd1385SRemy Bohmer * For example, isochronous endpoints can be autoconfigured for high 20223cd1385SRemy Bohmer * bandwidth, and then used in several lower bandwidth altsettings. 20323cd1385SRemy Bohmer * Also, high and full speed descriptors will be different. 20423cd1385SRemy Bohmer * 20523cd1385SRemy Bohmer * Be sure to examine and test the results of autoconfiguration on your 20623cd1385SRemy Bohmer * hardware. This code may not make the best choices about how to use the 20723cd1385SRemy Bohmer * USB controller, and it can't know all the restrictions that may apply. 20823cd1385SRemy Bohmer * Some combinations of driver and hardware won't be able to autoconfigure. 20923cd1385SRemy Bohmer * 21023cd1385SRemy Bohmer * On success, this returns an un-claimed usb_ep, and modifies the endpoint 21123cd1385SRemy Bohmer * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value 21223cd1385SRemy Bohmer * is initialized as if the endpoint were used at full speed. To prevent 21323cd1385SRemy Bohmer * the endpoint from being returned by a later autoconfig call, claim it 21423cd1385SRemy Bohmer * by assigning ep->driver_data to some non-null value. 21523cd1385SRemy Bohmer * 21623cd1385SRemy Bohmer * On failure, this returns a null endpoint descriptor. 21723cd1385SRemy Bohmer */ 21823cd1385SRemy Bohmer struct usb_ep *usb_ep_autoconfig( 21923cd1385SRemy Bohmer struct usb_gadget *gadget, 22023cd1385SRemy Bohmer struct usb_endpoint_descriptor *desc 22123cd1385SRemy Bohmer ) 22223cd1385SRemy Bohmer { 22316bece51SMarek Szyprowski struct usb_ep *ep = NULL; 22423cd1385SRemy Bohmer u8 type; 22523cd1385SRemy Bohmer 22623cd1385SRemy Bohmer type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 22723cd1385SRemy Bohmer 22823cd1385SRemy Bohmer /* First, apply chip-specific "best usage" knowledge. 22923cd1385SRemy Bohmer * This might make a good usb_gadget_ops hook ... 23023cd1385SRemy Bohmer */ 23123cd1385SRemy Bohmer if (gadget_is_net2280(gadget) && type == USB_ENDPOINT_XFER_INT) { 23223cd1385SRemy Bohmer /* ep-e, ep-f are PIO with only 64 byte fifos */ 23323cd1385SRemy Bohmer ep = find_ep(gadget, "ep-e"); 23423cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 23523cd1385SRemy Bohmer return ep; 23623cd1385SRemy Bohmer ep = find_ep(gadget, "ep-f"); 23723cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 23823cd1385SRemy Bohmer return ep; 23923cd1385SRemy Bohmer 24023cd1385SRemy Bohmer } else if (gadget_is_goku(gadget)) { 24123cd1385SRemy Bohmer if (USB_ENDPOINT_XFER_INT == type) { 24223cd1385SRemy Bohmer /* single buffering is enough */ 24323cd1385SRemy Bohmer ep = find_ep(gadget, "ep3-bulk"); 24423cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 24523cd1385SRemy Bohmer return ep; 24623cd1385SRemy Bohmer } else if (USB_ENDPOINT_XFER_BULK == type 24723cd1385SRemy Bohmer && (USB_DIR_IN & desc->bEndpointAddress)) { 24823cd1385SRemy Bohmer /* DMA may be available */ 24923cd1385SRemy Bohmer ep = find_ep(gadget, "ep2-bulk"); 25023cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 25123cd1385SRemy Bohmer return ep; 25223cd1385SRemy Bohmer } 25323cd1385SRemy Bohmer 25423cd1385SRemy Bohmer } else if (gadget_is_sh(gadget) && USB_ENDPOINT_XFER_INT == type) { 25523cd1385SRemy Bohmer /* single buffering is enough; maybe 8 byte fifo is too */ 25623cd1385SRemy Bohmer ep = find_ep(gadget, "ep3in-bulk"); 25723cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 25823cd1385SRemy Bohmer return ep; 25923cd1385SRemy Bohmer 26023cd1385SRemy Bohmer } else if (gadget_is_mq11xx(gadget) && USB_ENDPOINT_XFER_INT == type) { 26123cd1385SRemy Bohmer ep = find_ep(gadget, "ep1-bulk"); 26223cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 26323cd1385SRemy Bohmer return ep; 26416bece51SMarek Szyprowski } else if (gadget_is_dwc3(gadget)) { 26516bece51SMarek Szyprowski const char *name = NULL; 26616bece51SMarek Szyprowski /* 26716bece51SMarek Szyprowski * First try standard, common configuration: ep1in-bulk, 26816bece51SMarek Szyprowski * ep2out-bulk, ep3in-int to match other udc drivers to avoid 26916bece51SMarek Szyprowski * confusion in already deployed software (endpoint numbers 27016bece51SMarek Szyprowski * hardcoded in userspace software/drivers) 27116bece51SMarek Szyprowski */ 27216bece51SMarek Szyprowski if ((desc->bEndpointAddress & USB_DIR_IN) && 27316bece51SMarek Szyprowski type == USB_ENDPOINT_XFER_BULK) 27416bece51SMarek Szyprowski name = "ep1in"; 27516bece51SMarek Szyprowski else if ((desc->bEndpointAddress & USB_DIR_IN) == 0 && 27616bece51SMarek Szyprowski type == USB_ENDPOINT_XFER_BULK) 27716bece51SMarek Szyprowski name = "ep2out"; 27816bece51SMarek Szyprowski else if ((desc->bEndpointAddress & USB_DIR_IN) && 27916bece51SMarek Szyprowski type == USB_ENDPOINT_XFER_INT) 28016bece51SMarek Szyprowski name = "ep3in"; 28116bece51SMarek Szyprowski 28216bece51SMarek Szyprowski if (name) 28316bece51SMarek Szyprowski ep = find_ep(gadget, name); 28416bece51SMarek Szyprowski if (ep && ep_matches(gadget, ep, desc)) 28516bece51SMarek Szyprowski return ep; 28623cd1385SRemy Bohmer } 28723cd1385SRemy Bohmer 288*0943909dSVignesh Raghavendra if (gadget->ops->match_ep) 289*0943909dSVignesh Raghavendra ep = gadget->ops->match_ep(gadget, desc, NULL); 290*0943909dSVignesh Raghavendra 29123cd1385SRemy Bohmer /* Second, look at endpoints until an unclaimed one looks usable */ 29223cd1385SRemy Bohmer list_for_each_entry(ep, &gadget->ep_list, ep_list) { 29323cd1385SRemy Bohmer if (ep_matches(gadget, ep, desc)) 29423cd1385SRemy Bohmer return ep; 29523cd1385SRemy Bohmer } 29623cd1385SRemy Bohmer 29723cd1385SRemy Bohmer /* Fail */ 29823cd1385SRemy Bohmer return NULL; 29923cd1385SRemy Bohmer } 30023cd1385SRemy Bohmer 30123cd1385SRemy Bohmer /** 30223cd1385SRemy Bohmer * usb_ep_autoconfig_reset - reset endpoint autoconfig state 30323cd1385SRemy Bohmer * @gadget: device for which autoconfig state will be reset 30423cd1385SRemy Bohmer * 30523cd1385SRemy Bohmer * Use this for devices where one configuration may need to assign 30623cd1385SRemy Bohmer * endpoint resources very differently from the next one. It clears 30723cd1385SRemy Bohmer * state such as ep->driver_data and the record of assigned endpoints 30823cd1385SRemy Bohmer * used by usb_ep_autoconfig(). 30923cd1385SRemy Bohmer */ 31023cd1385SRemy Bohmer void usb_ep_autoconfig_reset(struct usb_gadget *gadget) 31123cd1385SRemy Bohmer { 31223cd1385SRemy Bohmer struct usb_ep *ep; 31323cd1385SRemy Bohmer 31423cd1385SRemy Bohmer list_for_each_entry(ep, &gadget->ep_list, ep_list) { 31523cd1385SRemy Bohmer ep->driver_data = NULL; 31623cd1385SRemy Bohmer } 31723cd1385SRemy Bohmer #ifdef MANY_ENDPOINTS 31823cd1385SRemy Bohmer in_epnum = 0; 31923cd1385SRemy Bohmer #endif 32023cd1385SRemy Bohmer epnum = 0; 32123cd1385SRemy Bohmer } 322