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