2008-06-20 04:52:58 +04:00
/*
* composite . c - infrastructure for Composite USB Gadgets
*
* Copyright ( C ) 2006 - 2008 David Brownell
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
/* #define VERBOSE_DEBUG */
# include <linux/kallsyms.h>
# include <linux/kernel.h>
# include <linux/slab.h>
2011-07-04 00:09:31 +04:00
# include <linux/module.h>
2008-06-20 04:52:58 +04:00
# include <linux/device.h>
2010-08-12 19:43:46 +04:00
# include <linux/utsname.h>
2008-06-20 04:52:58 +04:00
# include <linux/usb/composite.h>
2011-06-29 17:41:50 +04:00
# include <asm/unaligned.h>
2008-06-20 04:52:58 +04:00
/*
* The code in this file is utility code , used to build a gadget driver
* from one or more " function " drivers , one or more " configuration "
* objects , and a " usb_composite_driver " by gluing them together along
* with the relevant device - wide data .
*/
/* big enough to hold our biggest descriptor */
2010-03-30 16:14:01 +04:00
# define USB_BUFSIZ 1024
2008-06-20 04:52:58 +04:00
static struct usb_composite_driver * composite ;
2010-08-12 19:43:54 +04:00
static int ( * composite_gadget_bind ) ( struct usb_composite_dev * cdev ) ;
2008-06-20 04:52:58 +04:00
2011-03-31 05:57:33 +04:00
/* Some systems will need runtime overrides for the product identifiers
2008-06-20 04:52:58 +04:00
* published in the device descriptor , either numbers or strings or both .
* String parameters are in UTF - 8 ( superset of ASCII ' s 7 bit characters ) .
*/
static ushort idVendor ;
module_param ( idVendor , ushort , 0 ) ;
MODULE_PARM_DESC ( idVendor , " USB Vendor ID " ) ;
static ushort idProduct ;
module_param ( idProduct , ushort , 0 ) ;
MODULE_PARM_DESC ( idProduct , " USB Product ID " ) ;
static ushort bcdDevice ;
module_param ( bcdDevice , ushort , 0 ) ;
MODULE_PARM_DESC ( bcdDevice , " USB Device version (BCD) " ) ;
static char * iManufacturer ;
module_param ( iManufacturer , charp , 0 ) ;
MODULE_PARM_DESC ( iManufacturer , " USB Manufacturer string " ) ;
static char * iProduct ;
module_param ( iProduct , charp , 0 ) ;
MODULE_PARM_DESC ( iProduct , " USB Product string " ) ;
static char * iSerialNumber ;
module_param ( iSerialNumber , charp , 0 ) ;
MODULE_PARM_DESC ( iSerialNumber , " SerialNumber string " ) ;
2010-08-12 19:43:46 +04:00
static char composite_manufacturer [ 50 ] ;
2008-06-20 04:52:58 +04:00
/*-------------------------------------------------------------------------*/
2011-06-28 17:33:49 +04:00
/**
* next_ep_desc ( ) - advance to the next EP descriptor
* @ t : currect pointer within descriptor array
*
* Return : next EP descriptor or NULL
*
* Iterate over @ t until either EP descriptor found or
* NULL ( that indicates end of list ) encountered
*/
static struct usb_descriptor_header * *
next_ep_desc ( struct usb_descriptor_header * * t )
{
for ( ; * t ; t + + ) {
if ( ( * t ) - > bDescriptorType = = USB_DT_ENDPOINT )
return t ;
}
return NULL ;
}
/*
* for_each_ep_desc ( ) - iterate over endpoint descriptors in the
* descriptors list
* @ start : pointer within descriptor array .
* @ ep_desc : endpoint descriptor to use as the loop cursor
*/
# define for_each_ep_desc(start, ep_desc) \
for ( ep_desc = next_ep_desc ( start ) ; \
ep_desc ; ep_desc = next_ep_desc ( ep_desc + 1 ) )
/**
* config_ep_by_speed ( ) - configures the given endpoint
* according to gadget speed .
* @ g : pointer to the gadget
* @ f : usb function
* @ _ep : the endpoint to configure
*
* Return : error code , 0 on success
*
* This function chooses the right descriptors for a given
* endpoint according to gadget speed and saves it in the
* endpoint desc field . If the endpoint already has a descriptor
* assigned to it - overwrites it with currently corresponding
* descriptor . The endpoint maxpacket field is updated according
* to the chosen descriptor .
* Note : the supplied function should hold all the descriptors
* for supported speeds
*/
int config_ep_by_speed ( struct usb_gadget * g ,
struct usb_function * f ,
struct usb_ep * _ep )
{
struct usb_endpoint_descriptor * chosen_desc = NULL ;
struct usb_descriptor_header * * speed_desc = NULL ;
2011-06-29 17:41:50 +04:00
struct usb_ss_ep_comp_descriptor * comp_desc = NULL ;
int want_comp_desc = 0 ;
2011-06-28 17:33:49 +04:00
struct usb_descriptor_header * * d_spd ; /* cursor for speed desc */
if ( ! g | | ! f | | ! _ep )
return - EIO ;
/* select desired speed */
switch ( g - > speed ) {
2011-06-29 17:41:50 +04:00
case USB_SPEED_SUPER :
if ( gadget_is_superspeed ( g ) ) {
speed_desc = f - > ss_descriptors ;
want_comp_desc = 1 ;
break ;
}
/* else: Fall trough */
2011-06-28 17:33:49 +04:00
case USB_SPEED_HIGH :
if ( gadget_is_dualspeed ( g ) ) {
speed_desc = f - > hs_descriptors ;
break ;
}
/* else: fall through */
default :
speed_desc = f - > descriptors ;
}
/* find descriptors */
for_each_ep_desc ( speed_desc , d_spd ) {
chosen_desc = ( struct usb_endpoint_descriptor * ) * d_spd ;
if ( chosen_desc - > bEndpointAddress = = _ep - > address )
goto ep_found ;
}
return - EIO ;
ep_found :
/* commit results */
2011-08-23 14:12:03 +04:00
_ep - > maxpacket = usb_endpoint_maxp ( chosen_desc ) ;
2011-06-28 17:33:49 +04:00
_ep - > desc = chosen_desc ;
2011-06-29 17:41:50 +04:00
_ep - > comp_desc = NULL ;
_ep - > maxburst = 0 ;
_ep - > mult = 0 ;
if ( ! want_comp_desc )
return 0 ;
2011-06-28 17:33:49 +04:00
2011-06-29 17:41:50 +04:00
/*
* Companion descriptor should follow EP descriptor
* USB 3.0 spec , # 9.6 .7
*/
comp_desc = ( struct usb_ss_ep_comp_descriptor * ) * ( + + d_spd ) ;
if ( ! comp_desc | |
( comp_desc - > bDescriptorType ! = USB_DT_SS_ENDPOINT_COMP ) )
return - EIO ;
_ep - > comp_desc = comp_desc ;
if ( g - > speed = = USB_SPEED_SUPER ) {
switch ( usb_endpoint_type ( _ep - > desc ) ) {
case USB_ENDPOINT_XFER_ISOC :
/* mult: bits 1:0 of bmAttributes */
_ep - > mult = comp_desc - > bmAttributes & 0x3 ;
2012-01-17 01:24:38 +04:00
case USB_ENDPOINT_XFER_BULK :
case USB_ENDPOINT_XFER_INT :
_ep - > maxburst = comp_desc - > bMaxBurst ;
2011-06-29 17:41:50 +04:00
break ;
default :
/* Do nothing for control endpoints */
break ;
}
}
2011-06-28 17:33:49 +04:00
return 0 ;
}
2008-06-20 04:52:58 +04:00
/**
* usb_add_function ( ) - add a function to a configuration
* @ config : the configuration
* @ function : the function being added
* Context : single threaded during gadget setup
*
* After initialization , each configuration must have one or more
* functions added to it . Adding a function involves calling its @ bind ( )
* method to allocate resources such as interface and string identifiers
* and endpoints .
*
* This function returns the value of the function ' s bind ( ) , which is
* zero for success else a negative errno value .
*/
2010-05-05 14:53:13 +04:00
int usb_add_function ( struct usb_configuration * config ,
2008-06-20 04:52:58 +04:00
struct usb_function * function )
{
int value = - EINVAL ;
DBG ( config - > cdev , " adding '%s'/%p to config '%s'/%p \n " ,
function - > name , function ,
config - > label , config ) ;
if ( ! function - > set_alt | | ! function - > disable )
goto done ;
function - > config = config ;
list_add_tail ( & function - > list , & config - > functions ) ;
/* REVISIT *require* function->bind? */
if ( function - > bind ) {
value = function - > bind ( config , function ) ;
if ( value < 0 ) {
list_del ( & function - > list ) ;
function - > config = NULL ;
}
} else
value = 0 ;
/* We allow configurations that don't work at both speeds.
* If we run into a lowspeed Linux system , treat it the same
* as full speed . . . it ' s the function drivers that will need
* to avoid bulk and ISO transfers .
*/
if ( ! config - > fullspeed & & function - > descriptors )
config - > fullspeed = true ;
if ( ! config - > highspeed & & function - > hs_descriptors )
config - > highspeed = true ;
2011-06-29 17:41:50 +04:00
if ( ! config - > superspeed & & function - > ss_descriptors )
config - > superspeed = true ;
2008-06-20 04:52:58 +04:00
done :
if ( value )
DBG ( config - > cdev , " adding '%s'/%p --> %d \n " ,
function - > name , function , value ) ;
return value ;
}
2008-08-19 04:38:22 +04:00
/**
* usb_function_deactivate - prevent function and gadget enumeration
* @ function : the function that isn ' t yet ready to respond
*
* Blocks response of the gadget driver to host enumeration by
* preventing the data line pullup from being activated . This is
* normally called during @ bind ( ) processing to change from the
* initial " ready to respond " state , or when a required resource
* becomes available .
*
* For example , drivers that serve as a passthrough to a userspace
* daemon can block enumeration unless that daemon ( such as an OBEX ,
* MTP , or print server ) is ready to handle host requests .
*
* Not all systems support software control of their USB peripheral
* data pullups .
*
* Returns zero on success , else negative errno .
*/
int usb_function_deactivate ( struct usb_function * function )
{
struct usb_composite_dev * cdev = function - > config - > cdev ;
2009-02-12 16:09:47 +03:00
unsigned long flags ;
2008-08-19 04:38:22 +04:00
int status = 0 ;
2009-02-12 16:09:47 +03:00
spin_lock_irqsave ( & cdev - > lock , flags ) ;
2008-08-19 04:38:22 +04:00
if ( cdev - > deactivations = = 0 )
status = usb_gadget_disconnect ( cdev - > gadget ) ;
if ( status = = 0 )
cdev - > deactivations + + ;
2009-02-12 16:09:47 +03:00
spin_unlock_irqrestore ( & cdev - > lock , flags ) ;
2008-08-19 04:38:22 +04:00
return status ;
}
/**
* usb_function_activate - allow function and gadget enumeration
* @ function : function on which usb_function_activate ( ) was called
*
* Reverses effect of usb_function_deactivate ( ) . If no more functions
* are delaying their activation , the gadget driver will respond to
* host enumeration procedures .
*
* Returns zero on success , else negative errno .
*/
int usb_function_activate ( struct usb_function * function )
{
struct usb_composite_dev * cdev = function - > config - > cdev ;
int status = 0 ;
spin_lock ( & cdev - > lock ) ;
if ( WARN_ON ( cdev - > deactivations = = 0 ) )
status = - EINVAL ;
else {
cdev - > deactivations - - ;
if ( cdev - > deactivations = = 0 )
status = usb_gadget_connect ( cdev - > gadget ) ;
}
spin_unlock ( & cdev - > lock ) ;
return status ;
}
2008-06-20 04:52:58 +04:00
/**
* usb_interface_id ( ) - allocate an unused interface ID
* @ config : configuration associated with the interface
* @ function : function handling the interface
* Context : single threaded during gadget setup
*
* usb_interface_id ( ) is called from usb_function . bind ( ) callbacks to
* allocate new interface IDs . The function driver will then store that
* ID in interface , association , CDC union , and other descriptors . It
2011-03-31 05:57:33 +04:00
* will also handle any control requests targeted at that interface ,
2008-06-20 04:52:58 +04:00
* particularly changing its altsetting via set_alt ( ) . There may
* also be class - specific or vendor - specific requests to handle .
*
* All interface identifier should be allocated using this routine , to
* ensure that for example different functions don ' t wrongly assign
* different meanings to the same identifier . Note that since interface
2011-03-31 05:57:33 +04:00
* identifiers are configuration - specific , functions used in more than
2008-06-20 04:52:58 +04:00
* one configuration ( or more than once in a given configuration ) need
* multiple versions of the relevant descriptors .
*
* Returns the interface ID which was allocated ; or - ENODEV if no
* more interface IDs can be allocated .
*/
2010-05-05 14:53:13 +04:00
int usb_interface_id ( struct usb_configuration * config ,
2008-06-20 04:52:58 +04:00
struct usb_function * function )
{
unsigned id = config - > next_interface_id ;
if ( id < MAX_CONFIG_INTERFACES ) {
config - > interface [ id ] = function ;
config - > next_interface_id = id + 1 ;
return id ;
}
return - ENODEV ;
}
static int config_buf ( struct usb_configuration * config ,
enum usb_device_speed speed , void * buf , u8 type )
{
struct usb_config_descriptor * c = buf ;
void * next = buf + USB_DT_CONFIG_SIZE ;
int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE ;
struct usb_function * f ;
int status ;
/* write the config descriptor */
c = buf ;
c - > bLength = USB_DT_CONFIG_SIZE ;
c - > bDescriptorType = type ;
/* wTotalLength is written later */
c - > bNumInterfaces = config - > next_interface_id ;
c - > bConfigurationValue = config - > bConfigurationValue ;
c - > iConfiguration = config - > iConfiguration ;
c - > bmAttributes = USB_CONFIG_ATT_ONE | config - > bmAttributes ;
2008-09-12 20:39:06 +04:00
c - > bMaxPower = config - > bMaxPower ? : ( CONFIG_USB_GADGET_VBUS_DRAW / 2 ) ;
2008-06-20 04:52:58 +04:00
/* There may be e.g. OTG descriptors */
if ( config - > descriptors ) {
status = usb_descriptor_fillbuf ( next , len ,
config - > descriptors ) ;
if ( status < 0 )
return status ;
len - = status ;
next + = status ;
}
/* add each function's descriptors */
list_for_each_entry ( f , & config - > functions , list ) {
struct usb_descriptor_header * * descriptors ;
2011-06-29 17:41:50 +04:00
switch ( speed ) {
case USB_SPEED_SUPER :
descriptors = f - > ss_descriptors ;
break ;
case USB_SPEED_HIGH :
2008-06-20 04:52:58 +04:00
descriptors = f - > hs_descriptors ;
2011-06-29 17:41:50 +04:00
break ;
default :
2008-06-20 04:52:58 +04:00
descriptors = f - > descriptors ;
2011-06-29 17:41:50 +04:00
}
2008-06-20 04:52:58 +04:00
if ( ! descriptors )
continue ;
status = usb_descriptor_fillbuf ( next , len ,
( const struct usb_descriptor_header * * ) descriptors ) ;
if ( status < 0 )
return status ;
len - = status ;
next + = status ;
}
len = next - buf ;
c - > wTotalLength = cpu_to_le16 ( len ) ;
return len ;
}
static int config_desc ( struct usb_composite_dev * cdev , unsigned w_value )
{
struct usb_gadget * gadget = cdev - > gadget ;
struct usb_configuration * c ;
u8 type = w_value > > 8 ;
enum usb_device_speed speed = USB_SPEED_UNKNOWN ;
2011-06-29 17:41:50 +04:00
if ( gadget - > speed = = USB_SPEED_SUPER )
speed = gadget - > speed ;
else if ( gadget_is_dualspeed ( gadget ) ) {
int hs = 0 ;
2008-06-20 04:52:58 +04:00
if ( gadget - > speed = = USB_SPEED_HIGH )
hs = 1 ;
if ( type = = USB_DT_OTHER_SPEED_CONFIG )
hs = ! hs ;
if ( hs )
speed = USB_SPEED_HIGH ;
}
/* This is a lookup by config *INDEX* */
w_value & = 0xff ;
list_for_each_entry ( c , & cdev - > configs , list ) {
/* ignore configs that won't work at this speed */
2011-06-29 17:41:50 +04:00
switch ( speed ) {
case USB_SPEED_SUPER :
if ( ! c - > superspeed )
continue ;
break ;
case USB_SPEED_HIGH :
2008-06-20 04:52:58 +04:00
if ( ! c - > highspeed )
continue ;
2011-06-29 17:41:50 +04:00
break ;
default :
2008-06-20 04:52:58 +04:00
if ( ! c - > fullspeed )
continue ;
}
2011-06-29 17:41:50 +04:00
2008-06-20 04:52:58 +04:00
if ( w_value = = 0 )
return config_buf ( c , speed , cdev - > req - > buf , type ) ;
w_value - - ;
}
return - EINVAL ;
}
static int count_configs ( struct usb_composite_dev * cdev , unsigned type )
{
struct usb_gadget * gadget = cdev - > gadget ;
struct usb_configuration * c ;
unsigned count = 0 ;
int hs = 0 ;
2011-06-29 17:41:50 +04:00
int ss = 0 ;
2008-06-20 04:52:58 +04:00
if ( gadget_is_dualspeed ( gadget ) ) {
if ( gadget - > speed = = USB_SPEED_HIGH )
hs = 1 ;
2011-06-29 17:41:50 +04:00
if ( gadget - > speed = = USB_SPEED_SUPER )
ss = 1 ;
2008-06-20 04:52:58 +04:00
if ( type = = USB_DT_DEVICE_QUALIFIER )
hs = ! hs ;
}
list_for_each_entry ( c , & cdev - > configs , list ) {
/* ignore configs that won't work at this speed */
2011-06-29 17:41:50 +04:00
if ( ss ) {
if ( ! c - > superspeed )
continue ;
} else if ( hs ) {
2008-06-20 04:52:58 +04:00
if ( ! c - > highspeed )
continue ;
} else {
if ( ! c - > fullspeed )
continue ;
}
count + + ;
}
return count ;
}
2011-06-29 17:41:50 +04:00
/**
* bos_desc ( ) - prepares the BOS descriptor .
* @ cdev : pointer to usb_composite device to generate the bos
* descriptor for
*
* This function generates the BOS ( Binary Device Object )
* descriptor and its device capabilities descriptors . The BOS
* descriptor should be supported by a SuperSpeed device .
*/
static int bos_desc ( struct usb_composite_dev * cdev )
{
struct usb_ext_cap_descriptor * usb_ext ;
struct usb_ss_cap_descriptor * ss_cap ;
struct usb_dcd_config_params dcd_config_params ;
struct usb_bos_descriptor * bos = cdev - > req - > buf ;
bos - > bLength = USB_DT_BOS_SIZE ;
bos - > bDescriptorType = USB_DT_BOS ;
bos - > wTotalLength = cpu_to_le16 ( USB_DT_BOS_SIZE ) ;
bos - > bNumDeviceCaps = 0 ;
/*
* A SuperSpeed device shall include the USB2 .0 extension descriptor
* and shall support LPM when operating in USB2 .0 HS mode .
*/
usb_ext = cdev - > req - > buf + le16_to_cpu ( bos - > wTotalLength ) ;
bos - > bNumDeviceCaps + + ;
le16_add_cpu ( & bos - > wTotalLength , USB_DT_USB_EXT_CAP_SIZE ) ;
usb_ext - > bLength = USB_DT_USB_EXT_CAP_SIZE ;
usb_ext - > bDescriptorType = USB_DT_DEVICE_CAPABILITY ;
usb_ext - > bDevCapabilityType = USB_CAP_TYPE_EXT ;
usb_ext - > bmAttributes = cpu_to_le32 ( USB_LPM_SUPPORT ) ;
/*
* The Superspeed USB Capability descriptor shall be implemented by all
* SuperSpeed devices .
*/
ss_cap = cdev - > req - > buf + le16_to_cpu ( bos - > wTotalLength ) ;
bos - > bNumDeviceCaps + + ;
le16_add_cpu ( & bos - > wTotalLength , USB_DT_USB_SS_CAP_SIZE ) ;
ss_cap - > bLength = USB_DT_USB_SS_CAP_SIZE ;
ss_cap - > bDescriptorType = USB_DT_DEVICE_CAPABILITY ;
ss_cap - > bDevCapabilityType = USB_SS_CAP_TYPE ;
ss_cap - > bmAttributes = 0 ; /* LTM is not supported yet */
ss_cap - > wSpeedSupported = cpu_to_le16 ( USB_LOW_SPEED_OPERATION |
USB_FULL_SPEED_OPERATION |
USB_HIGH_SPEED_OPERATION |
USB_5GBPS_OPERATION ) ;
ss_cap - > bFunctionalitySupport = USB_LOW_SPEED_OPERATION ;
/* Get Controller configuration */
if ( cdev - > gadget - > ops - > get_config_params )
cdev - > gadget - > ops - > get_config_params ( & dcd_config_params ) ;
else {
2011-10-10 10:43:44 +04:00
dcd_config_params . bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT ;
2011-06-29 17:41:50 +04:00
dcd_config_params . bU2DevExitLat =
2011-10-10 10:43:44 +04:00
cpu_to_le16 ( USB_DEFAULT_U2_DEV_EXIT_LAT ) ;
2011-06-29 17:41:50 +04:00
}
ss_cap - > bU1devExitLat = dcd_config_params . bU1devExitLat ;
ss_cap - > bU2DevExitLat = dcd_config_params . bU2DevExitLat ;
return le16_to_cpu ( bos - > wTotalLength ) ;
}
2008-06-20 04:52:58 +04:00
static void device_qual ( struct usb_composite_dev * cdev )
{
struct usb_qualifier_descriptor * qual = cdev - > req - > buf ;
qual - > bLength = sizeof ( * qual ) ;
qual - > bDescriptorType = USB_DT_DEVICE_QUALIFIER ;
/* POLICY: same bcdUSB and device type info at both speeds */
qual - > bcdUSB = cdev - > desc . bcdUSB ;
qual - > bDeviceClass = cdev - > desc . bDeviceClass ;
qual - > bDeviceSubClass = cdev - > desc . bDeviceSubClass ;
qual - > bDeviceProtocol = cdev - > desc . bDeviceProtocol ;
/* ASSUME same EP0 fifo size at both speeds */
2011-06-23 16:26:11 +04:00
qual - > bMaxPacketSize0 = cdev - > gadget - > ep0 - > maxpacket ;
2008-06-20 04:52:58 +04:00
qual - > bNumConfigurations = count_configs ( cdev , USB_DT_DEVICE_QUALIFIER ) ;
2008-07-02 00:14:17 +04:00
qual - > bRESERVED = 0 ;
2008-06-20 04:52:58 +04:00
}
/*-------------------------------------------------------------------------*/
static void reset_config ( struct usb_composite_dev * cdev )
{
struct usb_function * f ;
DBG ( cdev , " reset config \n " ) ;
list_for_each_entry ( f , & cdev - > config - > functions , list ) {
if ( f - > disable )
f - > disable ( f ) ;
2009-10-21 02:03:38 +04:00
bitmap_zero ( f - > endpoints , 32 ) ;
2008-06-20 04:52:58 +04:00
}
cdev - > config = NULL ;
}
static int set_config ( struct usb_composite_dev * cdev ,
const struct usb_ctrlrequest * ctrl , unsigned number )
{
struct usb_gadget * gadget = cdev - > gadget ;
struct usb_configuration * c = NULL ;
int result = - EINVAL ;
unsigned power = gadget_is_otg ( gadget ) ? 8 : 100 ;
int tmp ;
if ( number ) {
list_for_each_entry ( c , & cdev - > configs , list ) {
if ( c - > bConfigurationValue = = number ) {
2011-06-29 17:41:50 +04:00
/*
* We disable the FDs of the previous
* configuration only if the new configuration
* is a valid one
*/
if ( cdev - > config )
reset_config ( cdev ) ;
2008-06-20 04:52:58 +04:00
result = 0 ;
break ;
}
}
if ( result < 0 )
goto done ;
2011-06-29 17:41:50 +04:00
} else { /* Zero configuration value - need to reset the config */
if ( cdev - > config )
reset_config ( cdev ) ;
2008-06-20 04:52:58 +04:00
result = 0 ;
2011-06-29 17:41:50 +04:00
}
2008-06-20 04:52:58 +04:00
2011-08-30 19:11:19 +04:00
INFO ( cdev , " %s config #%d: %s \n " ,
usb_speed_string ( gadget - > speed ) ,
number , c ? c - > label : " unconfigured " ) ;
2008-06-20 04:52:58 +04:00
if ( ! c )
goto done ;
cdev - > config = c ;
/* Initialize all interfaces by setting them to altsetting zero. */
for ( tmp = 0 ; tmp < MAX_CONFIG_INTERFACES ; tmp + + ) {
struct usb_function * f = c - > interface [ tmp ] ;
2009-10-21 02:03:38 +04:00
struct usb_descriptor_header * * descriptors ;
2008-06-20 04:52:58 +04:00
if ( ! f )
break ;
2009-10-21 02:03:38 +04:00
/*
* Record which endpoints are used by the function . This is used
* to dispatch control requests targeted at that endpoint to the
* function ' s setup callback instead of the current
* configuration ' s setup callback .
*/
2011-06-29 17:41:50 +04:00
switch ( gadget - > speed ) {
case USB_SPEED_SUPER :
descriptors = f - > ss_descriptors ;
break ;
case USB_SPEED_HIGH :
2009-10-21 02:03:38 +04:00
descriptors = f - > hs_descriptors ;
2011-06-29 17:41:50 +04:00
break ;
default :
2009-10-21 02:03:38 +04:00
descriptors = f - > descriptors ;
2011-06-29 17:41:50 +04:00
}
2009-10-21 02:03:38 +04:00
for ( ; * descriptors ; + + descriptors ) {
struct usb_endpoint_descriptor * ep ;
int addr ;
if ( ( * descriptors ) - > bDescriptorType ! = USB_DT_ENDPOINT )
continue ;
ep = ( struct usb_endpoint_descriptor * ) * descriptors ;
addr = ( ( ep - > bEndpointAddress & 0x80 ) > > 3 )
| ( ep - > bEndpointAddress & 0x0f ) ;
set_bit ( addr , f - > endpoints ) ;
}
2008-06-20 04:52:58 +04:00
result = f - > set_alt ( f , tmp , 0 ) ;
if ( result < 0 ) {
DBG ( cdev , " interface %d (%s/%p) alt 0 --> %d \n " ,
tmp , f - > name , f , result ) ;
reset_config ( cdev ) ;
goto done ;
}
2011-05-09 14:08:06 +04:00
if ( result = = USB_GADGET_DELAYED_STATUS ) {
DBG ( cdev ,
" %s: interface %d (%s) requested delayed status \n " ,
__func__ , tmp , f - > name ) ;
cdev - > delayed_status + + ;
DBG ( cdev , " delayed_status count %d \n " ,
cdev - > delayed_status ) ;
}
2008-06-20 04:52:58 +04:00
}
/* when we return, be sure our power usage is valid */
2008-09-12 20:39:06 +04:00
power = c - > bMaxPower ? ( 2 * c - > bMaxPower ) : CONFIG_USB_GADGET_VBUS_DRAW ;
2008-06-20 04:52:58 +04:00
done :
usb_gadget_vbus_draw ( gadget , power ) ;
2011-05-09 14:08:06 +04:00
if ( result > = 0 & & cdev - > delayed_status )
result = USB_GADGET_DELAYED_STATUS ;
2008-06-20 04:52:58 +04:00
return result ;
}
/**
* usb_add_config ( ) - add a configuration to a device .
* @ cdev : wraps the USB gadget
* @ config : the configuration , with bConfigurationValue assigned
2010-08-12 19:43:55 +04:00
* @ bind : the configuration ' s bind function
2008-06-20 04:52:58 +04:00
* Context : single threaded during gadget setup
*
2010-08-12 19:43:55 +04:00
* One of the main tasks of a composite @ bind ( ) routine is to
2008-06-20 04:52:58 +04:00
* add each of the configurations it supports , using this routine .
*
2010-08-12 19:43:55 +04:00
* This function returns the value of the configuration ' s @ bind ( ) , which
2008-06-20 04:52:58 +04:00
* is zero for success else a negative errno value . Binding configurations
* assigns global resources including string IDs , and per - configuration
* resources such as interface IDs and endpoints .
*/
2010-05-05 14:53:13 +04:00
int usb_add_config ( struct usb_composite_dev * cdev ,
2010-08-12 19:43:55 +04:00
struct usb_configuration * config ,
int ( * bind ) ( struct usb_configuration * ) )
2008-06-20 04:52:58 +04:00
{
int status = - EINVAL ;
struct usb_configuration * c ;
DBG ( cdev , " adding config #%u '%s'/%p \n " ,
config - > bConfigurationValue ,
config - > label , config ) ;
2010-08-12 19:43:55 +04:00
if ( ! config - > bConfigurationValue | | ! bind )
2008-06-20 04:52:58 +04:00
goto done ;
/* Prevent duplicate configuration identifiers */
list_for_each_entry ( c , & cdev - > configs , list ) {
if ( c - > bConfigurationValue = = config - > bConfigurationValue ) {
status = - EBUSY ;
goto done ;
}
}
config - > cdev = cdev ;
list_add_tail ( & config - > list , & cdev - > configs ) ;
INIT_LIST_HEAD ( & config - > functions ) ;
config - > next_interface_id = 0 ;
2010-08-12 19:43:55 +04:00
status = bind ( config ) ;
2008-06-20 04:52:58 +04:00
if ( status < 0 ) {
2012-03-20 05:38:38 +04:00
while ( ! list_empty ( & config - > functions ) ) {
struct usb_function * f ;
f = list_first_entry ( & config - > functions ,
struct usb_function , list ) ;
list_del ( & f - > list ) ;
if ( f - > unbind ) {
DBG ( cdev , " unbind function '%s'/%p \n " ,
f - > name , f ) ;
f - > unbind ( config , f ) ;
/* may free memory for "f" */
}
}
2008-06-20 04:52:58 +04:00
list_del ( & config - > list ) ;
config - > cdev = NULL ;
} else {
unsigned i ;
2011-06-29 17:41:50 +04:00
DBG ( cdev , " cfg %d/%p speeds:%s%s%s \n " ,
2008-06-20 04:52:58 +04:00
config - > bConfigurationValue , config ,
2011-06-29 17:41:50 +04:00
config - > superspeed ? " super " : " " ,
2008-06-20 04:52:58 +04:00
config - > highspeed ? " high " : " " ,
config - > fullspeed
? ( gadget_is_dualspeed ( cdev - > gadget )
? " full "
: " full/low " )
: " " ) ;
for ( i = 0 ; i < MAX_CONFIG_INTERFACES ; i + + ) {
struct usb_function * f = config - > interface [ i ] ;
if ( ! f )
continue ;
DBG ( cdev , " interface %d = %s/%p \n " ,
i , f - > name , f ) ;
}
}
2010-08-12 19:43:55 +04:00
/* set_alt(), or next bind(), sets up
2008-06-20 04:52:58 +04:00
* ep - > driver_data as needed .
*/
usb_ep_autoconfig_reset ( cdev - > gadget ) ;
done :
if ( status )
DBG ( cdev , " added config '%s'/%u --> %d \n " , config - > label ,
config - > bConfigurationValue , status ) ;
return status ;
}
/*-------------------------------------------------------------------------*/
/* We support strings in multiple languages ... string descriptor zero
* says which languages are supported . The typical case will be that
* only one language ( probably English ) is used , with I18N handled on
* the host side .
*/
static void collect_langs ( struct usb_gadget_strings * * sp , __le16 * buf )
{
const struct usb_gadget_strings * s ;
u16 language ;
__le16 * tmp ;
while ( * sp ) {
s = * sp ;
language = cpu_to_le16 ( s - > language ) ;
for ( tmp = buf ; * tmp & & tmp < & buf [ 126 ] ; tmp + + ) {
if ( * tmp = = language )
goto repeat ;
}
* tmp + + = language ;
repeat :
sp + + ;
}
}
static int lookup_string (
struct usb_gadget_strings * * sp ,
void * buf ,
u16 language ,
int id
)
{
struct usb_gadget_strings * s ;
int value ;
while ( * sp ) {
s = * sp + + ;
if ( s - > language ! = language )
continue ;
value = usb_gadget_get_string ( s , id , buf ) ;
if ( value > 0 )
return value ;
}
return - EINVAL ;
}
static int get_string ( struct usb_composite_dev * cdev ,
void * buf , u16 language , int id )
{
struct usb_configuration * c ;
struct usb_function * f ;
int len ;
2010-08-12 19:43:46 +04:00
const char * str ;
2008-06-20 04:52:58 +04:00
/* Yes, not only is USB's I18N support probably more than most
* folk will ever care about . . . also , it ' s all supported here .
* ( Except for UTF8 support for Unicode ' s " Astral Planes " . )
*/
/* 0 == report all available language codes */
if ( id = = 0 ) {
struct usb_string_descriptor * s = buf ;
struct usb_gadget_strings * * sp ;
memset ( s , 0 , 256 ) ;
s - > bDescriptorType = USB_DT_STRING ;
sp = composite - > strings ;
if ( sp )
collect_langs ( sp , s - > wData ) ;
list_for_each_entry ( c , & cdev - > configs , list ) {
sp = c - > strings ;
if ( sp )
collect_langs ( sp , s - > wData ) ;
list_for_each_entry ( f , & c - > functions , list ) {
sp = f - > strings ;
if ( sp )
collect_langs ( sp , s - > wData ) ;
}
}
2009-08-07 03:09:51 +04:00
for ( len = 0 ; len < = 126 & & s - > wData [ len ] ; len + + )
2008-06-20 04:52:58 +04:00
continue ;
if ( ! len )
return - EINVAL ;
s - > bLength = 2 * ( len + 1 ) ;
return s - > bLength ;
}
2010-08-12 19:43:46 +04:00
/* Otherwise, look up and return a specified string. First
* check if the string has not been overridden .
*/
if ( cdev - > manufacturer_override = = id )
str = iManufacturer ? : composite - > iManufacturer ? :
composite_manufacturer ;
else if ( cdev - > product_override = = id )
str = iProduct ? : composite - > iProduct ;
else if ( cdev - > serial_override = = id )
str = iSerialNumber ;
else
str = NULL ;
if ( str ) {
struct usb_gadget_strings strings = {
. language = language ,
. strings = & ( struct usb_string ) { 0xff , str }
} ;
return usb_gadget_get_string ( & strings , 0xff , buf ) ;
}
/* String IDs are device-scoped, so we look up each string
* table we ' re told about . These lookups are infrequent ;
* simpler - is - better here .
2008-06-20 04:52:58 +04:00
*/
if ( composite - > strings ) {
len = lookup_string ( composite - > strings , buf , language , id ) ;
if ( len > 0 )
return len ;
}
list_for_each_entry ( c , & cdev - > configs , list ) {
if ( c - > strings ) {
len = lookup_string ( c - > strings , buf , language , id ) ;
if ( len > 0 )
return len ;
}
list_for_each_entry ( f , & c - > functions , list ) {
if ( ! f - > strings )
continue ;
len = lookup_string ( f - > strings , buf , language , id ) ;
if ( len > 0 )
return len ;
}
}
return - EINVAL ;
}
/**
* usb_string_id ( ) - allocate an unused string ID
* @ cdev : the device whose string descriptor IDs are being allocated
* Context : single threaded during gadget setup
*
* @ usb_string_id ( ) is called from bind ( ) callbacks to allocate
* string IDs . Drivers for functions , configurations , or gadgets will
* then store that ID in the appropriate descriptors and string table .
*
2010-06-16 14:07:59 +04:00
* All string identifier should be allocated using this ,
* @ usb_string_ids_tab ( ) or @ usb_string_ids_n ( ) routine , to ensure
* that for example different functions don ' t wrongly assign different
* meanings to the same identifier .
2008-06-20 04:52:58 +04:00
*/
2010-05-05 14:53:13 +04:00
int usb_string_id ( struct usb_composite_dev * cdev )
2008-06-20 04:52:58 +04:00
{
if ( cdev - > next_string_id < 254 ) {
2010-06-16 14:07:59 +04:00
/* string id 0 is reserved by USB spec for list of
* supported languages */
/* 255 reserved as well? -- mina86 */
2008-06-20 04:52:58 +04:00
cdev - > next_string_id + + ;
return cdev - > next_string_id ;
}
return - ENODEV ;
}
2010-06-16 14:07:59 +04:00
/**
* usb_string_ids ( ) - allocate unused string IDs in batch
* @ cdev : the device whose string descriptor IDs are being allocated
* @ str : an array of usb_string objects to assign numbers to
* Context : single threaded during gadget setup
*
* @ usb_string_ids ( ) is called from bind ( ) callbacks to allocate
* string IDs . Drivers for functions , configurations , or gadgets will
* then copy IDs from the string table to the appropriate descriptors
* and string table for other languages .
*
* All string identifier should be allocated using this ,
* @ usb_string_id ( ) or @ usb_string_ids_n ( ) routine , to ensure that for
* example different functions don ' t wrongly assign different meanings
* to the same identifier .
*/
int usb_string_ids_tab ( struct usb_composite_dev * cdev , struct usb_string * str )
{
int next = cdev - > next_string_id ;
for ( ; str - > s ; + + str ) {
if ( unlikely ( next > = 254 ) )
return - ENODEV ;
str - > id = + + next ;
}
cdev - > next_string_id = next ;
return 0 ;
}
/**
* usb_string_ids_n ( ) - allocate unused string IDs in batch
2010-08-11 23:07:13 +04:00
* @ c : the device whose string descriptor IDs are being allocated
2010-06-16 14:07:59 +04:00
* @ n : number of string IDs to allocate
* Context : single threaded during gadget setup
*
* Returns the first requested ID . This ID and next @ n - 1 IDs are now
2010-08-11 23:07:13 +04:00
* valid IDs . At least provided that @ n is non - zero because if it
2010-06-16 14:07:59 +04:00
* is , returns last requested ID which is now very useful information .
*
* @ usb_string_ids_n ( ) is called from bind ( ) callbacks to allocate
* string IDs . Drivers for functions , configurations , or gadgets will
* then store that ID in the appropriate descriptors and string table .
*
* All string identifier should be allocated using this ,
* @ usb_string_id ( ) or @ usb_string_ids_n ( ) routine , to ensure that for
* example different functions don ' t wrongly assign different meanings
* to the same identifier .
*/
int usb_string_ids_n ( struct usb_composite_dev * c , unsigned n )
{
unsigned next = c - > next_string_id ;
if ( unlikely ( n > 254 | | ( unsigned ) next + n > 254 ) )
return - ENODEV ;
c - > next_string_id + = n ;
return next + 1 ;
}
2008-06-20 04:52:58 +04:00
/*-------------------------------------------------------------------------*/
static void composite_setup_complete ( struct usb_ep * ep , struct usb_request * req )
{
if ( req - > status | | req - > actual ! = req - > length )
DBG ( ( struct usb_composite_dev * ) ep - > driver_data ,
" setup complete --> %d, %d/%d \n " ,
req - > status , req - > actual , req - > length ) ;
}
/*
* The setup ( ) callback implements all the ep0 functionality that ' s
* not handled lower down , in hardware or the hardware driver ( like
* device and endpoint feature flags , and their status ) . It ' s all
* housekeeping for the gadget function we ' re implementing . Most of
* the work is in config and function specific setup .
*/
static int
composite_setup ( struct usb_gadget * gadget , const struct usb_ctrlrequest * ctrl )
{
struct usb_composite_dev * cdev = get_gadget_data ( gadget ) ;
struct usb_request * req = cdev - > req ;
int value = - EOPNOTSUPP ;
2011-06-29 17:41:50 +04:00
int status = 0 ;
2008-06-20 04:52:58 +04:00
u16 w_index = le16_to_cpu ( ctrl - > wIndex ) ;
2009-01-07 19:21:19 +03:00
u8 intf = w_index & 0xFF ;
2008-06-20 04:52:58 +04:00
u16 w_value = le16_to_cpu ( ctrl - > wValue ) ;
u16 w_length = le16_to_cpu ( ctrl - > wLength ) ;
struct usb_function * f = NULL ;
2009-10-21 02:03:38 +04:00
u8 endp ;
2008-06-20 04:52:58 +04:00
/* partial re-init of the response message; the function or the
* gadget might need to intercept e . g . a control - OUT completion
* when we delegate to it .
*/
req - > zero = 0 ;
req - > complete = composite_setup_complete ;
2011-02-22 16:38:42 +03:00
req - > length = 0 ;
2008-06-20 04:52:58 +04:00
gadget - > ep0 - > driver_data = cdev ;
switch ( ctrl - > bRequest ) {
/* we handle all standard USB descriptors */
case USB_REQ_GET_DESCRIPTOR :
if ( ctrl - > bRequestType ! = USB_DIR_IN )
goto unknown ;
switch ( w_value > > 8 ) {
case USB_DT_DEVICE :
cdev - > desc . bNumConfigurations =
count_configs ( cdev , USB_DT_DEVICE ) ;
2011-06-29 17:41:50 +04:00
cdev - > desc . bMaxPacketSize0 =
cdev - > gadget - > ep0 - > maxpacket ;
if ( gadget_is_superspeed ( gadget ) ) {
2011-07-19 22:21:52 +04:00
if ( gadget - > speed > = USB_SPEED_SUPER ) {
2011-06-29 17:41:50 +04:00
cdev - > desc . bcdUSB = cpu_to_le16 ( 0x0300 ) ;
2011-07-19 22:21:52 +04:00
cdev - > desc . bMaxPacketSize0 = 9 ;
} else {
2011-06-29 17:41:50 +04:00
cdev - > desc . bcdUSB = cpu_to_le16 ( 0x0210 ) ;
2011-07-19 22:21:52 +04:00
}
2011-06-29 17:41:50 +04:00
}
2008-06-20 04:52:58 +04:00
value = min ( w_length , ( u16 ) sizeof cdev - > desc ) ;
memcpy ( req - > buf , & cdev - > desc , value ) ;
break ;
case USB_DT_DEVICE_QUALIFIER :
2011-06-29 17:41:50 +04:00
if ( ! gadget_is_dualspeed ( gadget ) | |
gadget - > speed > = USB_SPEED_SUPER )
2008-06-20 04:52:58 +04:00
break ;
device_qual ( cdev ) ;
value = min_t ( int , w_length ,
sizeof ( struct usb_qualifier_descriptor ) ) ;
break ;
case USB_DT_OTHER_SPEED_CONFIG :
2011-06-29 17:41:50 +04:00
if ( ! gadget_is_dualspeed ( gadget ) | |
gadget - > speed > = USB_SPEED_SUPER )
2008-06-20 04:52:58 +04:00
break ;
/* FALLTHROUGH */
case USB_DT_CONFIG :
value = config_desc ( cdev , w_value ) ;
if ( value > = 0 )
value = min ( w_length , ( u16 ) value ) ;
break ;
case USB_DT_STRING :
value = get_string ( cdev , req - > buf ,
w_index , w_value & 0xff ) ;
if ( value > = 0 )
value = min ( w_length , ( u16 ) value ) ;
break ;
2011-06-29 17:41:50 +04:00
case USB_DT_BOS :
if ( gadget_is_superspeed ( gadget ) ) {
value = bos_desc ( cdev ) ;
value = min ( w_length , ( u16 ) value ) ;
}
break ;
2008-06-20 04:52:58 +04:00
}
break ;
/* any number of configs can work */
case USB_REQ_SET_CONFIGURATION :
if ( ctrl - > bRequestType ! = 0 )
goto unknown ;
if ( gadget_is_otg ( gadget ) ) {
if ( gadget - > a_hnp_support )
DBG ( cdev , " HNP available \n " ) ;
else if ( gadget - > a_alt_hnp_support )
DBG ( cdev , " HNP on another port \n " ) ;
else
VDBG ( cdev , " HNP inactive \n " ) ;
}
spin_lock ( & cdev - > lock ) ;
value = set_config ( cdev , ctrl , w_value ) ;
spin_unlock ( & cdev - > lock ) ;
break ;
case USB_REQ_GET_CONFIGURATION :
if ( ctrl - > bRequestType ! = USB_DIR_IN )
goto unknown ;
if ( cdev - > config )
* ( u8 * ) req - > buf = cdev - > config - > bConfigurationValue ;
else
* ( u8 * ) req - > buf = 0 ;
value = min ( w_length , ( u16 ) 1 ) ;
break ;
/* function drivers must handle get/set altsetting; if there's
* no get ( ) method , we know only altsetting zero works .
*/
case USB_REQ_SET_INTERFACE :
if ( ctrl - > bRequestType ! = USB_RECIP_INTERFACE )
goto unknown ;
2011-02-06 11:39:17 +03:00
if ( ! cdev - > config | | intf > = MAX_CONFIG_INTERFACES )
2008-06-20 04:52:58 +04:00
break ;
2009-01-07 19:21:19 +03:00
f = cdev - > config - > interface [ intf ] ;
2008-06-20 04:52:58 +04:00
if ( ! f )
break ;
2009-01-07 19:21:18 +03:00
if ( w_value & & ! f - > set_alt )
2008-06-20 04:52:58 +04:00
break ;
value = f - > set_alt ( f , w_index , w_value ) ;
2011-05-09 14:08:06 +04:00
if ( value = = USB_GADGET_DELAYED_STATUS ) {
DBG ( cdev ,
" %s: interface %d (%s) requested delayed status \n " ,
__func__ , intf , f - > name ) ;
cdev - > delayed_status + + ;
DBG ( cdev , " delayed_status count %d \n " ,
cdev - > delayed_status ) ;
}
2008-06-20 04:52:58 +04:00
break ;
case USB_REQ_GET_INTERFACE :
if ( ctrl - > bRequestType ! = ( USB_DIR_IN | USB_RECIP_INTERFACE ) )
goto unknown ;
2011-02-06 11:39:17 +03:00
if ( ! cdev - > config | | intf > = MAX_CONFIG_INTERFACES )
2008-06-20 04:52:58 +04:00
break ;
2009-01-07 19:21:19 +03:00
f = cdev - > config - > interface [ intf ] ;
2008-06-20 04:52:58 +04:00
if ( ! f )
break ;
/* lots of interfaces only need altsetting zero... */
value = f - > get_alt ? f - > get_alt ( f , w_index ) : 0 ;
if ( value < 0 )
break ;
* ( ( u8 * ) req - > buf ) = value ;
value = min ( w_length , ( u16 ) 1 ) ;
break ;
2011-06-29 17:41:50 +04:00
/*
* USB 3.0 additions :
* Function driver should handle get_status request . If such cb
* wasn ' t supplied we respond with default value = 0
* Note : function driver should supply such cb only for the first
* interface of the function
*/
case USB_REQ_GET_STATUS :
if ( ! gadget_is_superspeed ( gadget ) )
goto unknown ;
if ( ctrl - > bRequestType ! = ( USB_DIR_IN | USB_RECIP_INTERFACE ) )
goto unknown ;
value = 2 ; /* This is the length of the get_status reply */
put_unaligned_le16 ( 0 , req - > buf ) ;
if ( ! cdev - > config | | intf > = MAX_CONFIG_INTERFACES )
break ;
f = cdev - > config - > interface [ intf ] ;
if ( ! f )
break ;
status = f - > get_status ? f - > get_status ( f ) : 0 ;
if ( status < 0 )
break ;
put_unaligned_le16 ( status & 0x0000ffff , req - > buf ) ;
break ;
/*
* Function drivers should handle SetFeature / ClearFeature
* ( FUNCTION_SUSPEND ) request . function_suspend cb should be supplied
* only for the first interface of the function
*/
case USB_REQ_CLEAR_FEATURE :
case USB_REQ_SET_FEATURE :
if ( ! gadget_is_superspeed ( gadget ) )
goto unknown ;
if ( ctrl - > bRequestType ! = ( USB_DIR_OUT | USB_RECIP_INTERFACE ) )
goto unknown ;
switch ( w_value ) {
case USB_INTRF_FUNC_SUSPEND :
if ( ! cdev - > config | | intf > = MAX_CONFIG_INTERFACES )
break ;
f = cdev - > config - > interface [ intf ] ;
if ( ! f )
break ;
value = 0 ;
if ( f - > func_suspend )
value = f - > func_suspend ( f , w_index > > 8 ) ;
if ( value < 0 ) {
ERROR ( cdev ,
" func_suspend() returned error %d \n " ,
value ) ;
value = 0 ;
}
break ;
}
break ;
2008-06-20 04:52:58 +04:00
default :
unknown :
VDBG ( cdev ,
" non-core control req%02x.%02x v%04x i%04x l%d \n " ,
ctrl - > bRequestType , ctrl - > bRequest ,
w_value , w_index , w_length ) ;
2009-10-21 02:03:38 +04:00
/* functions always handle their interfaces and endpoints...
* punt other recipients ( other , WUSB , . . . ) to the current
2008-06-20 04:52:58 +04:00
* configuration code .
*
* REVISIT it could make sense to let the composite device
* take such requests too , if that ' s ever needed : to work
* in config 0 , etc .
*/
2009-10-21 02:03:38 +04:00
switch ( ctrl - > bRequestType & USB_RECIP_MASK ) {
case USB_RECIP_INTERFACE :
2011-02-06 11:39:17 +03:00
if ( ! cdev - > config | | intf > = MAX_CONFIG_INTERFACES )
2011-01-13 15:49:56 +03:00
break ;
f = cdev - > config - > interface [ intf ] ;
2009-10-21 02:03:38 +04:00
break ;
case USB_RECIP_ENDPOINT :
endp = ( ( w_index & 0x80 ) > > 3 ) | ( w_index & 0x0f ) ;
list_for_each_entry ( f , & cdev - > config - > functions , list ) {
if ( test_bit ( endp , f - > endpoints ) )
break ;
}
if ( & f - > list = = & cdev - > config - > functions )
2008-06-20 04:52:58 +04:00
f = NULL ;
2009-10-21 02:03:38 +04:00
break ;
2008-06-20 04:52:58 +04:00
}
2009-10-21 02:03:38 +04:00
if ( f & & f - > setup )
value = f - > setup ( f , ctrl ) ;
else {
2008-06-20 04:52:58 +04:00
struct usb_configuration * c ;
c = cdev - > config ;
if ( c & & c - > setup )
value = c - > setup ( c , ctrl ) ;
}
goto done ;
}
/* respond with data transfer before status phase? */
2011-05-09 14:08:06 +04:00
if ( value > = 0 & & value ! = USB_GADGET_DELAYED_STATUS ) {
2008-06-20 04:52:58 +04:00
req - > length = value ;
req - > zero = value < w_length ;
value = usb_ep_queue ( gadget - > ep0 , req , GFP_ATOMIC ) ;
if ( value < 0 ) {
DBG ( cdev , " ep_queue --> %d \n " , value ) ;
req - > status = 0 ;
composite_setup_complete ( gadget - > ep0 , req ) ;
}
2011-05-09 14:08:06 +04:00
} else if ( value = = USB_GADGET_DELAYED_STATUS & & w_length ! = 0 ) {
WARN ( cdev ,
" %s: Delayed status not supported for w_length != 0 " ,
__func__ ) ;
2008-06-20 04:52:58 +04:00
}
done :
/* device either stalls (value < 0) or reports success */
return value ;
}
static void composite_disconnect ( struct usb_gadget * gadget )
{
struct usb_composite_dev * cdev = get_gadget_data ( gadget ) ;
unsigned long flags ;
/* REVISIT: should we have config and device level
* disconnect callbacks ?
*/
spin_lock_irqsave ( & cdev - > lock , flags ) ;
if ( cdev - > config )
reset_config ( cdev ) ;
2010-06-21 15:57:08 +04:00
if ( composite - > disconnect )
composite - > disconnect ( cdev ) ;
2008-06-20 04:52:58 +04:00
spin_unlock_irqrestore ( & cdev - > lock , flags ) ;
}
/*-------------------------------------------------------------------------*/
2010-04-23 16:21:26 +04:00
static ssize_t composite_show_suspended ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct usb_gadget * gadget = dev_to_usb_gadget ( dev ) ;
struct usb_composite_dev * cdev = get_gadget_data ( gadget ) ;
return sprintf ( buf , " %d \n " , cdev - > suspended ) ;
}
static DEVICE_ATTR ( suspended , 0444 , composite_show_suspended , NULL ) ;
2010-05-05 14:53:13 +04:00
static void
2008-06-20 04:52:58 +04:00
composite_unbind ( struct usb_gadget * gadget )
{
struct usb_composite_dev * cdev = get_gadget_data ( gadget ) ;
/* composite_disconnect() must already have been called
* by the underlying peripheral controller driver !
* so there ' s no i / o concurrency that could affect the
* state protected by cdev - > lock .
*/
WARN_ON ( cdev - > config ) ;
while ( ! list_empty ( & cdev - > configs ) ) {
struct usb_configuration * c ;
c = list_first_entry ( & cdev - > configs ,
struct usb_configuration , list ) ;
while ( ! list_empty ( & c - > functions ) ) {
struct usb_function * f ;
f = list_first_entry ( & c - > functions ,
struct usb_function , list ) ;
list_del ( & f - > list ) ;
if ( f - > unbind ) {
DBG ( cdev , " unbind function '%s'/%p \n " ,
f - > name , f ) ;
f - > unbind ( c , f ) ;
/* may free memory for "f" */
}
}
list_del ( & c - > list ) ;
if ( c - > unbind ) {
DBG ( cdev , " unbind config '%s'/%p \n " , c - > label , c ) ;
c - > unbind ( c ) ;
/* may free memory for "c" */
}
}
if ( composite - > unbind )
composite - > unbind ( cdev ) ;
if ( cdev - > req ) {
kfree ( cdev - > req - > buf ) ;
usb_ep_free_request ( gadget - > ep0 , cdev - > req ) ;
}
2010-12-16 12:02:25 +03:00
device_remove_file ( & gadget - > dev , & dev_attr_suspended ) ;
2008-06-20 04:52:58 +04:00
kfree ( cdev ) ;
set_gadget_data ( gadget , NULL ) ;
composite = NULL ;
}
2010-08-12 19:43:46 +04:00
static u8 override_id ( struct usb_composite_dev * cdev , u8 * desc )
2008-06-20 04:52:58 +04:00
{
2010-08-12 19:43:46 +04:00
if ( ! * desc ) {
int ret = usb_string_id ( cdev ) ;
if ( unlikely ( ret < 0 ) )
WARNING ( cdev , " failed to override string ID \n " ) ;
else
* desc = ret ;
2008-06-20 04:52:58 +04:00
}
2010-08-12 19:43:46 +04:00
return * desc ;
2008-06-20 04:52:58 +04:00
}
2010-05-05 14:53:13 +04:00
static int composite_bind ( struct usb_gadget * gadget )
2008-06-20 04:52:58 +04:00
{
struct usb_composite_dev * cdev ;
int status = - ENOMEM ;
cdev = kzalloc ( sizeof * cdev , GFP_KERNEL ) ;
if ( ! cdev )
return status ;
spin_lock_init ( & cdev - > lock ) ;
cdev - > gadget = gadget ;
set_gadget_data ( gadget , cdev ) ;
INIT_LIST_HEAD ( & cdev - > configs ) ;
/* preallocate control response and buffer */
cdev - > req = usb_ep_alloc_request ( gadget - > ep0 , GFP_KERNEL ) ;
if ( ! cdev - > req )
goto fail ;
cdev - > req - > buf = kmalloc ( USB_BUFSIZ , GFP_KERNEL ) ;
if ( ! cdev - > req - > buf )
goto fail ;
cdev - > req - > complete = composite_setup_complete ;
gadget - > ep0 - > driver_data = cdev ;
cdev - > bufsiz = USB_BUFSIZ ;
cdev - > driver = composite ;
2010-08-25 15:03:26 +04:00
/*
* As per USB compliance update , a device that is actively drawing
* more than 100 mA from USB must report itself as bus - powered in
* the GetStatus ( DEVICE ) call .
*/
if ( CONFIG_USB_GADGET_VBUS_DRAW < = USB_SELF_POWER_VBUS_MAX_DRAW )
usb_gadget_set_selfpowered ( gadget ) ;
2008-06-20 04:52:58 +04:00
/* interface and string IDs start at zero via kzalloc.
* we force endpoints to start unassigned ; few controller
* drivers will zero ep - > driver_data .
*/
usb_ep_autoconfig_reset ( cdev - > gadget ) ;
/* composite gadget needs to assign strings for whole device (like
* serial number ) , register function drivers , potentially update
* power state and consumption , etc
*/
2010-08-12 19:43:54 +04:00
status = composite_gadget_bind ( cdev ) ;
2008-06-20 04:52:58 +04:00
if ( status < 0 )
goto fail ;
cdev - > desc = * composite - > dev ;
2010-12-17 02:52:30 +03:00
/* standardized runtime overrides for device ID data */
if ( idVendor )
cdev - > desc . idVendor = cpu_to_le16 ( idVendor ) ;
if ( idProduct )
cdev - > desc . idProduct = cpu_to_le16 ( idProduct ) ;
if ( bcdDevice )
cdev - > desc . bcdDevice = cpu_to_le16 ( bcdDevice ) ;
2010-10-27 12:19:01 +04:00
/* string overrides */
2010-08-12 19:43:46 +04:00
if ( iManufacturer | | ! cdev - > desc . iManufacturer ) {
if ( ! iManufacturer & & ! composite - > iManufacturer & &
! * composite_manufacturer )
snprintf ( composite_manufacturer ,
sizeof composite_manufacturer ,
" %s %s with %s " ,
init_utsname ( ) - > sysname ,
init_utsname ( ) - > release ,
gadget - > name ) ;
cdev - > manufacturer_override =
override_id ( cdev , & cdev - > desc . iManufacturer ) ;
}
if ( iProduct | | ( ! cdev - > desc . iProduct & & composite - > iProduct ) )
cdev - > product_override =
override_id ( cdev , & cdev - > desc . iProduct ) ;
if ( iSerialNumber )
cdev - > serial_override =
override_id ( cdev , & cdev - > desc . iSerialNumber ) ;
/* has userspace failed to provide a serial number? */
if ( composite - > needs_serial & & ! cdev - > desc . iSerialNumber )
WARNING ( cdev , " userspace failed to provide iSerialNumber \n " ) ;
2008-06-20 04:52:58 +04:00
2010-08-12 19:43:46 +04:00
/* finish up */
2010-04-23 16:21:26 +04:00
status = device_create_file ( & gadget - > dev , & dev_attr_suspended ) ;
if ( status )
goto fail ;
2008-06-20 04:52:58 +04:00
INFO ( cdev , " %s ready \n " , composite - > name ) ;
return 0 ;
fail :
composite_unbind ( gadget ) ;
return status ;
}
/*-------------------------------------------------------------------------*/
static void
composite_suspend ( struct usb_gadget * gadget )
{
struct usb_composite_dev * cdev = get_gadget_data ( gadget ) ;
struct usb_function * f ;
2009-03-20 00:14:17 +03:00
/* REVISIT: should we have config level
2008-06-20 04:52:58 +04:00
* suspend / resume callbacks ?
*/
DBG ( cdev , " suspend \n " ) ;
if ( cdev - > config ) {
list_for_each_entry ( f , & cdev - > config - > functions , list ) {
if ( f - > suspend )
f - > suspend ( f ) ;
}
}
2009-03-20 00:14:17 +03:00
if ( composite - > suspend )
composite - > suspend ( cdev ) ;
2010-04-23 16:21:26 +04:00
cdev - > suspended = 1 ;
2010-11-29 10:17:03 +03:00
usb_gadget_vbus_draw ( gadget , 2 ) ;
2008-06-20 04:52:58 +04:00
}
static void
composite_resume ( struct usb_gadget * gadget )
{
struct usb_composite_dev * cdev = get_gadget_data ( gadget ) ;
struct usb_function * f ;
2010-11-29 10:17:03 +03:00
u8 maxpower ;
2008-06-20 04:52:58 +04:00
2009-03-20 00:14:17 +03:00
/* REVISIT: should we have config level
2008-06-20 04:52:58 +04:00
* suspend / resume callbacks ?
*/
DBG ( cdev , " resume \n " ) ;
2009-03-20 00:14:17 +03:00
if ( composite - > resume )
composite - > resume ( cdev ) ;
2008-06-20 04:52:58 +04:00
if ( cdev - > config ) {
list_for_each_entry ( f , & cdev - > config - > functions , list ) {
if ( f - > resume )
f - > resume ( f ) ;
}
2010-11-29 10:17:03 +03:00
maxpower = cdev - > config - > bMaxPower ;
usb_gadget_vbus_draw ( gadget , maxpower ?
( 2 * maxpower ) : CONFIG_USB_GADGET_VBUS_DRAW ) ;
2008-06-20 04:52:58 +04:00
}
2010-04-23 16:21:26 +04:00
cdev - > suspended = 0 ;
2008-06-20 04:52:58 +04:00
}
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver composite_driver = {
2011-06-29 17:41:50 +04:00
# ifdef CONFIG_USB_GADGET_SUPERSPEED
2011-11-19 21:27:38 +04:00
. max_speed = USB_SPEED_SUPER ,
2011-06-29 17:41:50 +04:00
# else
2011-11-19 21:27:38 +04:00
. max_speed = USB_SPEED_HIGH ,
2011-06-29 17:41:50 +04:00
# endif
2008-06-20 04:52:58 +04:00
2009-11-09 16:15:25 +03:00
. unbind = composite_unbind ,
2008-06-20 04:52:58 +04:00
. setup = composite_setup ,
. disconnect = composite_disconnect ,
. suspend = composite_suspend ,
. resume = composite_resume ,
. driver = {
. owner = THIS_MODULE ,
} ,
} ;
/**
2010-08-12 19:43:54 +04:00
* usb_composite_probe ( ) - register a composite driver
2008-06-20 04:52:58 +04:00
* @ driver : the driver to register
2010-08-12 19:43:54 +04:00
* @ bind : the callback used to allocate resources that are shared across the
* whole device , such as string IDs , and add its configurations using
* @ usb_add_config ( ) . This may fail by returning a negative errno
* value ; it should return zero on successful initialization .
2008-06-20 04:52:58 +04:00
* Context : single threaded during gadget setup
*
* This function is used to register drivers using the composite driver
* framework . The return value is zero , or a negative errno value .
* Those values normally come from the driver ' s @ bind method , which does
* all the work of setting up the driver to match the hardware .
*
* On successful return , the gadget is ready to respond to requests from
* the host , unless one of its components invokes usb_gadget_disconnect ( )
* while it was binding . That would usually be done in order to wait for
* some userspace participation .
*/
2011-02-06 12:47:18 +03:00
int usb_composite_probe ( struct usb_composite_driver * driver ,
2010-08-12 19:43:54 +04:00
int ( * bind ) ( struct usb_composite_dev * cdev ) )
2008-06-20 04:52:58 +04:00
{
2010-08-12 19:43:54 +04:00
if ( ! driver | | ! driver - > dev | | ! bind | | composite )
2008-06-20 04:52:58 +04:00
return - EINVAL ;
if ( ! driver - > name )
driver - > name = " composite " ;
2011-02-06 12:47:18 +03:00
if ( ! driver - > iProduct )
driver - > iProduct = driver - > name ;
2008-06-20 04:52:58 +04:00
composite_driver . function = ( char * ) driver - > name ;
composite_driver . driver . name = driver - > name ;
2011-11-19 21:27:38 +04:00
composite_driver . max_speed =
min_t ( u8 , composite_driver . max_speed , driver - > max_speed ) ;
2008-06-20 04:52:58 +04:00
composite = driver ;
2010-08-12 19:43:54 +04:00
composite_gadget_bind = bind ;
2008-06-20 04:52:58 +04:00
2010-08-12 19:43:53 +04:00
return usb_gadget_probe_driver ( & composite_driver , composite_bind ) ;
2008-06-20 04:52:58 +04:00
}
/**
* usb_composite_unregister ( ) - unregister a composite driver
* @ driver : the driver to unregister
*
* This function is used to unregister drivers using the composite
* driver framework .
*/
2010-05-05 14:53:13 +04:00
void usb_composite_unregister ( struct usb_composite_driver * driver )
2008-06-20 04:52:58 +04:00
{
if ( composite ! = driver )
return ;
usb_gadget_unregister_driver ( & composite_driver ) ;
}
2011-05-09 14:08:06 +04:00
/**
* usb_composite_setup_continue ( ) - Continue with the control transfer
* @ cdev : the composite device who ' s control transfer was kept waiting
*
* This function must be called by the USB function driver to continue
* with the control transfer ' s data / status stage in case it had requested to
* delay the data / status stages . A USB function ' s setup handler ( e . g . set_alt ( ) )
* can request the composite framework to delay the setup request ' s data / status
* stages by returning USB_GADGET_DELAYED_STATUS .
*/
void usb_composite_setup_continue ( struct usb_composite_dev * cdev )
{
int value ;
struct usb_request * req = cdev - > req ;
unsigned long flags ;
DBG ( cdev , " %s \n " , __func__ ) ;
spin_lock_irqsave ( & cdev - > lock , flags ) ;
if ( cdev - > delayed_status = = 0 ) {
WARN ( cdev , " %s: Unexpected call \n " , __func__ ) ;
} else if ( - - cdev - > delayed_status = = 0 ) {
DBG ( cdev , " %s: Completing delayed status \n " , __func__ ) ;
req - > length = 0 ;
value = usb_ep_queue ( cdev - > gadget - > ep0 , req , GFP_ATOMIC ) ;
if ( value < 0 ) {
DBG ( cdev , " ep_queue --> %d \n " , value ) ;
req - > status = 0 ;
composite_setup_complete ( cdev - > gadget - > ep0 , req ) ;
}
}
spin_unlock_irqrestore ( & cdev - > lock , flags ) ;
}