123cd1385SRemy Bohmer /* 223cd1385SRemy Bohmer * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers 323cd1385SRemy Bohmer * 423cd1385SRemy Bohmer * Copyright (C) 2004 David Brownell 523cd1385SRemy Bohmer * 623cd1385SRemy Bohmer * This program is free software; you can redistribute it and/or modify 723cd1385SRemy Bohmer * it under the terms of the GNU General Public License as published by 823cd1385SRemy Bohmer * the Free Software Foundation; either version 2 of the License, or 923cd1385SRemy Bohmer * (at your option) any later version. 1023cd1385SRemy Bohmer * 1123cd1385SRemy Bohmer * This program is distributed in the hope that it will be useful, 1223cd1385SRemy Bohmer * but WITHOUT ANY WARRANTY; without even the implied warranty of 1323cd1385SRemy Bohmer * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1423cd1385SRemy Bohmer * GNU General Public License for more details. 1523cd1385SRemy Bohmer * 1623cd1385SRemy Bohmer * You should have received a copy of the GNU General Public License 1723cd1385SRemy Bohmer * along with this program; if not, write to the Free Software 1823cd1385SRemy Bohmer * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1923cd1385SRemy Bohmer * 2023cd1385SRemy Bohmer * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and 2123cd1385SRemy Bohmer * Remy Bohmer <linux@bohmer.net> 2223cd1385SRemy Bohmer */ 2323cd1385SRemy Bohmer 2423cd1385SRemy Bohmer #include <common.h> 2523cd1385SRemy Bohmer #include <linux/usb/ch9.h> 2623cd1385SRemy Bohmer #include <asm/errno.h> 2723cd1385SRemy Bohmer #include <linux/usb/gadget.h> 2823cd1385SRemy Bohmer #include "gadget_chips.h" 2923cd1385SRemy Bohmer 3023cd1385SRemy Bohmer #define isdigit(c) ('0' <= (c) && (c) <= '9') 3123cd1385SRemy Bohmer 3223cd1385SRemy Bohmer /* we must assign addresses for configurable endpoints (like net2280) */ 3323cd1385SRemy Bohmer static unsigned epnum; 3423cd1385SRemy Bohmer 35*6142e0aeSVitaly Kuzmichev /* #define MANY_ENDPOINTS */ 3623cd1385SRemy Bohmer #ifdef MANY_ENDPOINTS 3723cd1385SRemy Bohmer /* more than 15 configurable endpoints */ 3823cd1385SRemy Bohmer static unsigned in_epnum; 3923cd1385SRemy Bohmer #endif 4023cd1385SRemy Bohmer 4123cd1385SRemy Bohmer 4223cd1385SRemy Bohmer /* 4323cd1385SRemy Bohmer * This should work with endpoints from controller drivers sharing the 4423cd1385SRemy Bohmer * same endpoint naming convention. By example: 4523cd1385SRemy Bohmer * 4623cd1385SRemy Bohmer * - ep1, ep2, ... address is fixed, not direction or type 4723cd1385SRemy Bohmer * - ep1in, ep2out, ... address and direction are fixed, not type 4823cd1385SRemy Bohmer * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction 4923cd1385SRemy Bohmer * - ep1in-bulk, ep2out-iso, ... all three are fixed 5023cd1385SRemy Bohmer * - ep-* ... no functionality restrictions 5123cd1385SRemy Bohmer * 5223cd1385SRemy Bohmer * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal. 5323cd1385SRemy Bohmer * Less common restrictions are implied by gadget_is_*(). 5423cd1385SRemy Bohmer * 5523cd1385SRemy Bohmer * NOTE: each endpoint is unidirectional, as specified by its USB 5623cd1385SRemy Bohmer * descriptor; and isn't specific to a configuration or altsetting. 5723cd1385SRemy Bohmer */ 58*6142e0aeSVitaly Kuzmichev static int ep_matches( 5923cd1385SRemy Bohmer struct usb_gadget *gadget, 6023cd1385SRemy Bohmer struct usb_ep *ep, 6123cd1385SRemy Bohmer struct usb_endpoint_descriptor *desc 6223cd1385SRemy Bohmer ) 6323cd1385SRemy Bohmer { 6423cd1385SRemy Bohmer u8 type; 6523cd1385SRemy Bohmer const char *tmp; 6623cd1385SRemy Bohmer u16 max; 6723cd1385SRemy Bohmer 6823cd1385SRemy Bohmer /* endpoint already claimed? */ 6923cd1385SRemy Bohmer if (NULL != ep->driver_data) 7023cd1385SRemy Bohmer return 0; 7123cd1385SRemy Bohmer 7223cd1385SRemy Bohmer /* only support ep0 for portable CONTROL traffic */ 7323cd1385SRemy Bohmer type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 7423cd1385SRemy Bohmer if (USB_ENDPOINT_XFER_CONTROL == type) 7523cd1385SRemy Bohmer return 0; 7623cd1385SRemy Bohmer 7723cd1385SRemy Bohmer /* some other naming convention */ 7823cd1385SRemy Bohmer if ('e' != ep->name[0]) 7923cd1385SRemy Bohmer return 0; 8023cd1385SRemy Bohmer 8123cd1385SRemy Bohmer /* type-restriction: "-iso", "-bulk", or "-int". 8223cd1385SRemy Bohmer * direction-restriction: "in", "out". 8323cd1385SRemy Bohmer */ 8423cd1385SRemy Bohmer if ('-' != ep->name[2]) { 8523cd1385SRemy Bohmer tmp = strrchr(ep->name, '-'); 8623cd1385SRemy Bohmer if (tmp) { 8723cd1385SRemy Bohmer switch (type) { 8823cd1385SRemy Bohmer case USB_ENDPOINT_XFER_INT: 8923cd1385SRemy Bohmer /* bulk endpoints handle interrupt transfers, 9023cd1385SRemy Bohmer * except the toggle-quirky iso-synch kind 9123cd1385SRemy Bohmer */ 92*6142e0aeSVitaly Kuzmichev if ('s' == tmp[2]) /* == "-iso" */ 9323cd1385SRemy Bohmer return 0; 9423cd1385SRemy Bohmer /* for now, avoid PXA "interrupt-in"; 9523cd1385SRemy Bohmer * it's documented as never using DATA1. 9623cd1385SRemy Bohmer */ 9723cd1385SRemy Bohmer if (gadget_is_pxa(gadget) 9823cd1385SRemy Bohmer && 'i' == tmp[1]) 9923cd1385SRemy Bohmer return 0; 10023cd1385SRemy Bohmer break; 10123cd1385SRemy Bohmer case USB_ENDPOINT_XFER_BULK: 102*6142e0aeSVitaly Kuzmichev if ('b' != tmp[1]) /* != "-bulk" */ 10323cd1385SRemy Bohmer return 0; 10423cd1385SRemy Bohmer break; 10523cd1385SRemy Bohmer case USB_ENDPOINT_XFER_ISOC: 106*6142e0aeSVitaly Kuzmichev if ('s' != tmp[2]) /* != "-iso" */ 10723cd1385SRemy Bohmer return 0; 10823cd1385SRemy Bohmer } 10923cd1385SRemy Bohmer } else { 11023cd1385SRemy Bohmer tmp = ep->name + strlen(ep->name); 11123cd1385SRemy Bohmer } 11223cd1385SRemy Bohmer 11323cd1385SRemy Bohmer /* direction-restriction: "..in-..", "out-.." */ 11423cd1385SRemy Bohmer tmp--; 11523cd1385SRemy Bohmer if (!isdigit(*tmp)) { 11623cd1385SRemy Bohmer if (desc->bEndpointAddress & USB_DIR_IN) { 11723cd1385SRemy Bohmer if ('n' != *tmp) 11823cd1385SRemy Bohmer return 0; 11923cd1385SRemy Bohmer } else { 12023cd1385SRemy Bohmer if ('t' != *tmp) 12123cd1385SRemy Bohmer return 0; 12223cd1385SRemy Bohmer } 12323cd1385SRemy Bohmer } 12423cd1385SRemy Bohmer } 12523cd1385SRemy Bohmer 12623cd1385SRemy Bohmer /* endpoint maxpacket size is an input parameter, except for bulk 12723cd1385SRemy Bohmer * where it's an output parameter representing the full speed limit. 12823cd1385SRemy Bohmer * the usb spec fixes high speed bulk maxpacket at 512 bytes. 12923cd1385SRemy Bohmer */ 13023cd1385SRemy Bohmer max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize); 13123cd1385SRemy Bohmer switch (type) { 13223cd1385SRemy Bohmer case USB_ENDPOINT_XFER_INT: 13323cd1385SRemy Bohmer /* INT: limit 64 bytes full speed, 1024 high speed */ 13423cd1385SRemy Bohmer if (!gadget->is_dualspeed && max > 64) 13523cd1385SRemy Bohmer return 0; 13623cd1385SRemy Bohmer /* FALLTHROUGH */ 13723cd1385SRemy Bohmer 13823cd1385SRemy Bohmer case USB_ENDPOINT_XFER_ISOC: 13923cd1385SRemy Bohmer /* ISO: limit 1023 bytes full speed, 1024 high speed */ 14023cd1385SRemy Bohmer if (ep->maxpacket < max) 14123cd1385SRemy Bohmer return 0; 14223cd1385SRemy Bohmer if (!gadget->is_dualspeed && max > 1023) 14323cd1385SRemy Bohmer return 0; 14423cd1385SRemy Bohmer 14523cd1385SRemy Bohmer /* BOTH: "high bandwidth" works only at high speed */ 14623cd1385SRemy Bohmer if ((desc->wMaxPacketSize & __constant_cpu_to_le16(3<<11))) { 14723cd1385SRemy Bohmer if (!gadget->is_dualspeed) 14823cd1385SRemy Bohmer return 0; 14923cd1385SRemy Bohmer /* configure your hardware with enough buffering!! */ 15023cd1385SRemy Bohmer } 15123cd1385SRemy Bohmer break; 15223cd1385SRemy Bohmer } 15323cd1385SRemy Bohmer 15423cd1385SRemy Bohmer /* MATCH!! */ 15523cd1385SRemy Bohmer 15623cd1385SRemy Bohmer /* report address */ 15723cd1385SRemy Bohmer if (isdigit(ep->name[2])) { 158c0ef5131SVitaly Kuzmichev u8 num = simple_strtoul(&ep->name[2], NULL, 10); 15923cd1385SRemy Bohmer desc->bEndpointAddress |= num; 16023cd1385SRemy Bohmer #ifdef MANY_ENDPOINTS 16123cd1385SRemy Bohmer } else if (desc->bEndpointAddress & USB_DIR_IN) { 16223cd1385SRemy Bohmer if (++in_epnum > 15) 16323cd1385SRemy Bohmer return 0; 16423cd1385SRemy Bohmer desc->bEndpointAddress = USB_DIR_IN | in_epnum; 16523cd1385SRemy Bohmer #endif 16623cd1385SRemy Bohmer } else { 16723cd1385SRemy Bohmer if (++epnum > 15) 16823cd1385SRemy Bohmer return 0; 16923cd1385SRemy Bohmer desc->bEndpointAddress |= epnum; 17023cd1385SRemy Bohmer } 17123cd1385SRemy Bohmer 17223cd1385SRemy Bohmer /* report (variable) full speed bulk maxpacket */ 17323cd1385SRemy Bohmer if (USB_ENDPOINT_XFER_BULK == type) { 17423cd1385SRemy Bohmer int size = ep->maxpacket; 17523cd1385SRemy Bohmer 17623cd1385SRemy Bohmer /* min() doesn't work on bitfields with gcc-3.5 */ 17723cd1385SRemy Bohmer if (size > 64) 17823cd1385SRemy Bohmer size = 64; 17923cd1385SRemy Bohmer desc->wMaxPacketSize = cpu_to_le16(size); 18023cd1385SRemy Bohmer } 18123cd1385SRemy Bohmer return 1; 18223cd1385SRemy Bohmer } 18323cd1385SRemy Bohmer 18423cd1385SRemy Bohmer static struct usb_ep * 18523cd1385SRemy Bohmer find_ep(struct usb_gadget *gadget, const char *name) 18623cd1385SRemy Bohmer { 18723cd1385SRemy Bohmer struct usb_ep *ep; 18823cd1385SRemy Bohmer 18923cd1385SRemy Bohmer list_for_each_entry(ep, &gadget->ep_list, ep_list) { 19023cd1385SRemy Bohmer if (0 == strcmp(ep->name, name)) 19123cd1385SRemy Bohmer return ep; 19223cd1385SRemy Bohmer } 19323cd1385SRemy Bohmer return NULL; 19423cd1385SRemy Bohmer } 19523cd1385SRemy Bohmer 19623cd1385SRemy Bohmer /** 19723cd1385SRemy Bohmer * usb_ep_autoconfig - choose an endpoint matching the descriptor 19823cd1385SRemy Bohmer * @gadget: The device to which the endpoint must belong. 19923cd1385SRemy Bohmer * @desc: Endpoint descriptor, with endpoint direction and transfer mode 20023cd1385SRemy Bohmer * initialized. For periodic transfers, the maximum packet 20123cd1385SRemy Bohmer * size must also be initialized. This is modified on success. 20223cd1385SRemy Bohmer * 20323cd1385SRemy Bohmer * By choosing an endpoint to use with the specified descriptor, this 20423cd1385SRemy Bohmer * routine simplifies writing gadget drivers that work with multiple 20523cd1385SRemy Bohmer * USB device controllers. The endpoint would be passed later to 20623cd1385SRemy Bohmer * usb_ep_enable(), along with some descriptor. 20723cd1385SRemy Bohmer * 20823cd1385SRemy Bohmer * That second descriptor won't always be the same as the first one. 20923cd1385SRemy Bohmer * For example, isochronous endpoints can be autoconfigured for high 21023cd1385SRemy Bohmer * bandwidth, and then used in several lower bandwidth altsettings. 21123cd1385SRemy Bohmer * Also, high and full speed descriptors will be different. 21223cd1385SRemy Bohmer * 21323cd1385SRemy Bohmer * Be sure to examine and test the results of autoconfiguration on your 21423cd1385SRemy Bohmer * hardware. This code may not make the best choices about how to use the 21523cd1385SRemy Bohmer * USB controller, and it can't know all the restrictions that may apply. 21623cd1385SRemy Bohmer * Some combinations of driver and hardware won't be able to autoconfigure. 21723cd1385SRemy Bohmer * 21823cd1385SRemy Bohmer * On success, this returns an un-claimed usb_ep, and modifies the endpoint 21923cd1385SRemy Bohmer * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value 22023cd1385SRemy Bohmer * is initialized as if the endpoint were used at full speed. To prevent 22123cd1385SRemy Bohmer * the endpoint from being returned by a later autoconfig call, claim it 22223cd1385SRemy Bohmer * by assigning ep->driver_data to some non-null value. 22323cd1385SRemy Bohmer * 22423cd1385SRemy Bohmer * On failure, this returns a null endpoint descriptor. 22523cd1385SRemy Bohmer */ 22623cd1385SRemy Bohmer struct usb_ep *usb_ep_autoconfig( 22723cd1385SRemy Bohmer struct usb_gadget *gadget, 22823cd1385SRemy Bohmer struct usb_endpoint_descriptor *desc 22923cd1385SRemy Bohmer ) 23023cd1385SRemy Bohmer { 23123cd1385SRemy Bohmer struct usb_ep *ep; 23223cd1385SRemy Bohmer u8 type; 23323cd1385SRemy Bohmer 23423cd1385SRemy Bohmer type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 23523cd1385SRemy Bohmer 23623cd1385SRemy Bohmer /* First, apply chip-specific "best usage" knowledge. 23723cd1385SRemy Bohmer * This might make a good usb_gadget_ops hook ... 23823cd1385SRemy Bohmer */ 23923cd1385SRemy Bohmer if (gadget_is_net2280(gadget) && type == USB_ENDPOINT_XFER_INT) { 24023cd1385SRemy Bohmer /* ep-e, ep-f are PIO with only 64 byte fifos */ 24123cd1385SRemy Bohmer ep = find_ep(gadget, "ep-e"); 24223cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 24323cd1385SRemy Bohmer return ep; 24423cd1385SRemy Bohmer ep = find_ep(gadget, "ep-f"); 24523cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 24623cd1385SRemy Bohmer return ep; 24723cd1385SRemy Bohmer 24823cd1385SRemy Bohmer } else if (gadget_is_goku(gadget)) { 24923cd1385SRemy Bohmer if (USB_ENDPOINT_XFER_INT == type) { 25023cd1385SRemy Bohmer /* single buffering is enough */ 25123cd1385SRemy Bohmer ep = find_ep(gadget, "ep3-bulk"); 25223cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 25323cd1385SRemy Bohmer return ep; 25423cd1385SRemy Bohmer } else if (USB_ENDPOINT_XFER_BULK == type 25523cd1385SRemy Bohmer && (USB_DIR_IN & desc->bEndpointAddress)) { 25623cd1385SRemy Bohmer /* DMA may be available */ 25723cd1385SRemy Bohmer ep = find_ep(gadget, "ep2-bulk"); 25823cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 25923cd1385SRemy Bohmer return ep; 26023cd1385SRemy Bohmer } 26123cd1385SRemy Bohmer 26223cd1385SRemy Bohmer } else if (gadget_is_sh(gadget) && USB_ENDPOINT_XFER_INT == type) { 26323cd1385SRemy Bohmer /* single buffering is enough; maybe 8 byte fifo is too */ 26423cd1385SRemy Bohmer ep = find_ep(gadget, "ep3in-bulk"); 26523cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 26623cd1385SRemy Bohmer return ep; 26723cd1385SRemy Bohmer 26823cd1385SRemy Bohmer } else if (gadget_is_mq11xx(gadget) && USB_ENDPOINT_XFER_INT == type) { 26923cd1385SRemy Bohmer ep = find_ep(gadget, "ep1-bulk"); 27023cd1385SRemy Bohmer if (ep && ep_matches(gadget, ep, desc)) 27123cd1385SRemy Bohmer return ep; 27223cd1385SRemy Bohmer } 27323cd1385SRemy Bohmer 27423cd1385SRemy Bohmer /* Second, look at endpoints until an unclaimed one looks usable */ 27523cd1385SRemy Bohmer list_for_each_entry(ep, &gadget->ep_list, ep_list) { 27623cd1385SRemy Bohmer if (ep_matches(gadget, ep, desc)) 27723cd1385SRemy Bohmer return ep; 27823cd1385SRemy Bohmer } 27923cd1385SRemy Bohmer 28023cd1385SRemy Bohmer /* Fail */ 28123cd1385SRemy Bohmer return NULL; 28223cd1385SRemy Bohmer } 28323cd1385SRemy Bohmer 28423cd1385SRemy Bohmer /** 28523cd1385SRemy Bohmer * usb_ep_autoconfig_reset - reset endpoint autoconfig state 28623cd1385SRemy Bohmer * @gadget: device for which autoconfig state will be reset 28723cd1385SRemy Bohmer * 28823cd1385SRemy Bohmer * Use this for devices where one configuration may need to assign 28923cd1385SRemy Bohmer * endpoint resources very differently from the next one. It clears 29023cd1385SRemy Bohmer * state such as ep->driver_data and the record of assigned endpoints 29123cd1385SRemy Bohmer * used by usb_ep_autoconfig(). 29223cd1385SRemy Bohmer */ 29323cd1385SRemy Bohmer void usb_ep_autoconfig_reset(struct usb_gadget *gadget) 29423cd1385SRemy Bohmer { 29523cd1385SRemy Bohmer struct usb_ep *ep; 29623cd1385SRemy Bohmer 29723cd1385SRemy Bohmer list_for_each_entry(ep, &gadget->ep_list, ep_list) { 29823cd1385SRemy Bohmer ep->driver_data = NULL; 29923cd1385SRemy Bohmer } 30023cd1385SRemy Bohmer #ifdef MANY_ENDPOINTS 30123cd1385SRemy Bohmer in_epnum = 0; 30223cd1385SRemy Bohmer #endif 30323cd1385SRemy Bohmer epnum = 0; 30423cd1385SRemy Bohmer } 30523cd1385SRemy Bohmer 306