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 .
*/
2012-12-24 00:10:22 +04:00
static struct usb_gadget_strings * * get_containers_gs (
struct usb_gadget_string_container * uc )
{
return ( struct usb_gadget_strings * * ) uc - > stash ;
}
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 )
{
2012-06-06 11:20:23 +04:00
struct usb_composite_dev * cdev = get_gadget_data ( g ) ;
2011-06-28 17:33:49 +04:00
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 :
2012-10-23 00:15:06 +04:00
speed_desc = f - > fs_descriptors ;
2011-06-28 17:33:49 +04:00
}
/* 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 :
2012-06-06 11:20:23 +04:00
_ep - > maxburst = comp_desc - > bMaxBurst + 1 ;
2011-06-29 17:41:50 +04:00
break ;
default :
2012-06-06 11:20:23 +04:00
if ( comp_desc - > bMaxBurst ! = 0 )
ERROR ( cdev , " ep0 bMaxBurst must be 0 \n " ) ;
_ep - > maxburst = 1 ;
2011-06-29 17:41:50 +04:00
break ;
}
}
2011-06-28 17:33:49 +04:00
return 0 ;
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( config_ep_by_speed ) ;
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 .
*/
2012-10-23 00:15:06 +04:00
if ( ! config - > fullspeed & & function - > fs_descriptors )
2008-06-20 04:52:58 +04:00
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 ;
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_add_function ) ;
2008-06-20 04:52:58 +04:00
2012-12-24 00:10:05 +04:00
void usb_remove_function ( struct usb_configuration * c , struct usb_function * f )
{
if ( f - > disable )
f - > disable ( f ) ;
bitmap_zero ( f - > endpoints , 32 ) ;
list_del ( & f - > list ) ;
if ( f - > unbind )
f - > unbind ( c , f ) ;
}
EXPORT_SYMBOL_GPL ( usb_remove_function ) ;
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 ;
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_function_deactivate ) ;
2008-08-19 04:38:22 +04:00
/**
* 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 ;
2012-07-19 02:20:11 +04:00
unsigned long flags ;
2008-08-19 04:38:22 +04:00
int status = 0 ;
2012-07-19 02:20:11 +04:00
spin_lock_irqsave ( & cdev - > lock , flags ) ;
2008-08-19 04:38:22 +04:00
if ( WARN_ON ( cdev - > deactivations = = 0 ) )
status = - EINVAL ;
else {
cdev - > deactivations - - ;
if ( cdev - > deactivations = = 0 )
status = usb_gadget_connect ( cdev - > gadget ) ;
}
2012-07-19 02:20:11 +04:00
spin_unlock_irqrestore ( & cdev - > lock , flags ) ;
2008-08-19 04:38:22 +04:00
return status ;
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_function_activate ) ;
2008-08-19 04:38:22 +04:00
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 ;
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_interface_id ) ;
2008-06-20 04:52:58 +04:00
2012-12-03 23:07:05 +04:00
static u8 encode_bMaxPower ( enum usb_device_speed speed ,
struct usb_configuration * c )
{
unsigned val ;
if ( c - > MaxPower )
val = c - > MaxPower ;
else
val = CONFIG_USB_GADGET_VBUS_DRAW ;
if ( ! val )
return 0 ;
switch ( speed ) {
case USB_SPEED_SUPER :
return DIV_ROUND_UP ( val , 8 ) ;
default :
return DIV_ROUND_UP ( val , 2 ) ;
} ;
}
2008-06-20 04:52:58 +04:00
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 ;
2012-09-10 17:01:51 +04:00
int len ;
2008-06-20 04:52:58 +04:00
struct usb_function * f ;
int status ;
2012-09-10 17:01:51 +04:00
len = USB_COMP_EP0_BUFSIZ - USB_DT_CONFIG_SIZE ;
2008-06-20 04:52:58 +04:00
/* 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 ;
2012-12-03 23:07:05 +04:00
c - > bMaxPower = encode_bMaxPower ( speed , config ) ;
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 :
2012-10-23 00:15:06 +04:00
descriptors = f - > fs_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 :
2012-10-23 00:15:06 +04:00
descriptors = f - > fs_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 */
2012-12-03 23:07:05 +04:00
power = c - > MaxPower ? c - > MaxPower : 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 ;
}
2012-12-24 00:10:00 +04:00
int usb_add_config_only ( struct usb_composite_dev * cdev ,
struct usb_configuration * config )
{
struct usb_configuration * c ;
if ( ! config - > bConfigurationValue )
return - EINVAL ;
/* Prevent duplicate configuration identifiers */
list_for_each_entry ( c , & cdev - > configs , list ) {
if ( c - > bConfigurationValue = = config - > bConfigurationValue )
return - EBUSY ;
}
config - > cdev = cdev ;
list_add_tail ( & config - > list , & cdev - > configs ) ;
INIT_LIST_HEAD ( & config - > functions ) ;
config - > next_interface_id = 0 ;
memset ( config - > interface , 0 , sizeof ( config - > interface ) ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( usb_add_config_only ) ;
2008-06-20 04:52:58 +04:00
/**
* 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 ;
2012-12-24 00:10:00 +04:00
if ( ! bind )
goto done ;
2008-06-20 04:52:58 +04:00
DBG ( cdev , " adding config #%u '%s'/%p \n " ,
config - > bConfigurationValue ,
config - > label , config ) ;
2012-12-24 00:10:00 +04:00
status = usb_add_config_only ( cdev , config ) ;
if ( status )
2008-06-20 04:52:58 +04:00
goto done ;
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 ;
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_add_config ) ;
2008-06-20 04:52:58 +04:00
2012-05-10 12:07:57 +04:00
static void remove_config ( struct usb_composite_dev * cdev ,
struct usb_configuration * config )
{
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" */
}
}
list_del ( & config - > list ) ;
if ( config - > unbind ) {
DBG ( cdev , " unbind config '%s'/%p \n " , config - > label , config ) ;
config - > unbind ( config ) ;
/* may free memory for "c" */
}
}
/**
* usb_remove_config ( ) - remove a configuration from a device .
* @ cdev : wraps the USB gadget
* @ config : the configuration
*
* Drivers must call usb_gadget_disconnect before calling this function
* to disconnect the device from the host and make sure the host will not
* try to enumerate the device while we are changing the config list .
*/
void usb_remove_config ( struct usb_composite_dev * cdev ,
struct usb_configuration * config )
{
unsigned long flags ;
spin_lock_irqsave ( & cdev - > lock , flags ) ;
if ( cdev - > config = = config )
reset_config ( cdev ) ;
spin_unlock_irqrestore ( & cdev - > lock , flags ) ;
remove_config ( cdev , config ) ;
}
2008-06-20 04:52:58 +04:00
/*-------------------------------------------------------------------------*/
/* 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 ;
2012-04-17 10:30:22 +04:00
__le16 language ;
2008-06-20 04:52:58 +04:00
__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 )
{
2012-09-07 11:53:17 +04:00
struct usb_composite_driver * composite = cdev - > driver ;
2012-12-24 00:10:22 +04:00
struct usb_gadget_string_container * uc ;
2008-06-20 04:52:58 +04:00
struct usb_configuration * c ;
struct usb_function * f ;
int len ;
/* 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 ) ;
}
}
2012-12-24 00:10:23 +04:00
list_for_each_entry ( uc , & cdev - > gstrings , list ) {
struct usb_gadget_strings * * sp ;
sp = get_containers_gs ( uc ) ;
collect_langs ( sp , s - > wData ) ;
}
2008-06-20 04:52:58 +04:00
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 ;
}
2012-12-24 00:10:22 +04:00
list_for_each_entry ( uc , & cdev - > gstrings , list ) {
struct usb_gadget_strings * * sp ;
sp = get_containers_gs ( uc ) ;
len = lookup_string ( sp , buf , language , id ) ;
if ( len > 0 )
return len ;
}
2010-08-12 19:43:46 +04:00
/* 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 ;
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_string_id ) ;
2008-06-20 04:52:58 +04:00
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 ;
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_string_ids_tab ) ;
2010-06-16 14:07:59 +04:00
2012-12-24 00:10:22 +04:00
static struct usb_gadget_string_container * copy_gadget_strings (
struct usb_gadget_strings * * sp , unsigned n_gstrings ,
unsigned n_strings )
{
struct usb_gadget_string_container * uc ;
struct usb_gadget_strings * * gs_array ;
struct usb_gadget_strings * gs ;
struct usb_string * s ;
unsigned mem ;
unsigned n_gs ;
unsigned n_s ;
void * stash ;
mem = sizeof ( * uc ) ;
mem + = sizeof ( void * ) * ( n_gstrings + 1 ) ;
mem + = sizeof ( struct usb_gadget_strings ) * n_gstrings ;
mem + = sizeof ( struct usb_string ) * ( n_strings + 1 ) * ( n_gstrings ) ;
uc = kmalloc ( mem , GFP_KERNEL ) ;
if ( ! uc )
return ERR_PTR ( - ENOMEM ) ;
gs_array = get_containers_gs ( uc ) ;
stash = uc - > stash ;
stash + = sizeof ( void * ) * ( n_gstrings + 1 ) ;
for ( n_gs = 0 ; n_gs < n_gstrings ; n_gs + + ) {
struct usb_string * org_s ;
gs_array [ n_gs ] = stash ;
gs = gs_array [ n_gs ] ;
stash + = sizeof ( struct usb_gadget_strings ) ;
gs - > language = sp [ n_gs ] - > language ;
gs - > strings = stash ;
org_s = sp [ n_gs ] - > strings ;
for ( n_s = 0 ; n_s < n_strings ; n_s + + ) {
s = stash ;
stash + = sizeof ( struct usb_string ) ;
if ( org_s - > s )
s - > s = org_s - > s ;
else
s - > s = " " ;
org_s + + ;
}
s = stash ;
s - > s = NULL ;
stash + = sizeof ( struct usb_string ) ;
}
gs_array [ n_gs ] = NULL ;
return uc ;
}
/**
* usb_gstrings_attach ( ) - attach gadget strings to a cdev and assign ids
* @ cdev : the device whose string descriptor IDs are being allocated
* and attached .
* @ sp : an array of usb_gadget_strings to attach .
* @ n_strings : number of entries in each usb_strings array ( sp [ ] - > strings )
*
* This function will create a deep copy of usb_gadget_strings and usb_string
* and attach it to the cdev . The actual string ( usb_string . s ) will not be
* copied but only a referenced will be made . The struct usb_gadget_strings
* array may contain multiple languges and should be NULL terminated .
* The - > language pointer of each struct usb_gadget_strings has to contain the
* same amount of entries .
* For instance : sp [ 0 ] is en - US , sp [ 1 ] is es - ES . It is expected that the first
* usb_string entry of es - ES containts the translation of the first usb_string
* entry of en - US . Therefore both entries become the same id assign .
*/
struct usb_string * usb_gstrings_attach ( struct usb_composite_dev * cdev ,
struct usb_gadget_strings * * sp , unsigned n_strings )
{
struct usb_gadget_string_container * uc ;
struct usb_gadget_strings * * n_gs ;
unsigned n_gstrings = 0 ;
unsigned i ;
int ret ;
for ( i = 0 ; sp [ i ] ; i + + )
n_gstrings + + ;
if ( ! n_gstrings )
return ERR_PTR ( - EINVAL ) ;
uc = copy_gadget_strings ( sp , n_gstrings , n_strings ) ;
if ( IS_ERR ( uc ) )
return ERR_PTR ( PTR_ERR ( uc ) ) ;
n_gs = get_containers_gs ( uc ) ;
ret = usb_string_ids_tab ( cdev , n_gs [ 0 ] - > strings ) ;
if ( ret )
goto err ;
for ( i = 1 ; i < n_gstrings ; i + + ) {
struct usb_string * m_s ;
struct usb_string * s ;
unsigned n ;
m_s = n_gs [ 0 ] - > strings ;
s = n_gs [ i ] - > strings ;
for ( n = 0 ; n < n_strings ; n + + ) {
s - > id = m_s - > id ;
s + + ;
m_s + + ;
}
}
list_add_tail ( & uc - > list , & cdev - > gstrings ) ;
return n_gs [ 0 ] - > strings ;
err :
kfree ( uc ) ;
return ERR_PTR ( ret ) ;
}
EXPORT_SYMBOL_GPL ( usb_gstrings_attach ) ;
2010-06-16 14:07:59 +04:00
/**
* 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 ;
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_string_ids_n ) ;
2010-06-16 14:07:59 +04:00
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 .
*/
2012-12-24 00:10:21 +04:00
int
2008-06-20 04:52:58 +04:00
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 ;
}
2012-12-24 00:10:21 +04:00
void composite_disconnect ( struct usb_gadget * gadget )
2008-06-20 04:52:58 +04:00
{
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 ) ;
2012-09-07 11:53:17 +04:00
if ( cdev - > driver - > disconnect )
cdev - > driver - > 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 ) ;
2012-12-24 00:09:55 +04:00
static void __composite_unbind ( struct usb_gadget * gadget , bool unbind_driver )
2008-06-20 04:52:58 +04:00
{
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 ) ;
2012-05-10 12:07:57 +04:00
remove_config ( cdev , c ) ;
2008-06-20 04:52:58 +04:00
}
2012-12-24 00:09:55 +04:00
if ( cdev - > driver - > unbind & & unbind_driver )
2012-09-07 11:53:17 +04:00
cdev - > driver - > unbind ( cdev ) ;
2008-06-20 04:52:58 +04:00
2012-12-24 00:10:20 +04:00
composite_dev_cleanup ( cdev ) ;
2012-09-10 17:01:58 +04:00
kfree ( cdev - > def_manufacturer ) ;
2008-06-20 04:52:58 +04:00
kfree ( cdev ) ;
set_gadget_data ( gadget , NULL ) ;
}
2012-12-24 00:09:55 +04:00
static void composite_unbind ( struct usb_gadget * gadget )
{
__composite_unbind ( gadget , true ) ;
}
2012-09-10 17:01:53 +04:00
static void update_unchanged_dev_desc ( struct usb_device_descriptor * new ,
const struct usb_device_descriptor * old )
{
__le16 idVendor ;
__le16 idProduct ;
__le16 bcdDevice ;
2012-09-10 17:01:54 +04:00
u8 iSerialNumber ;
2012-09-10 17:01:55 +04:00
u8 iManufacturer ;
2012-09-10 17:01:56 +04:00
u8 iProduct ;
2012-09-10 17:01:53 +04:00
/*
* these variables may have been set in
* usb_composite_overwrite_options ( )
*/
idVendor = new - > idVendor ;
idProduct = new - > idProduct ;
bcdDevice = new - > bcdDevice ;
2012-09-10 17:01:54 +04:00
iSerialNumber = new - > iSerialNumber ;
2012-09-10 17:01:55 +04:00
iManufacturer = new - > iManufacturer ;
2012-09-10 17:01:56 +04:00
iProduct = new - > iProduct ;
2012-09-10 17:01:53 +04:00
* new = * old ;
if ( idVendor )
new - > idVendor = idVendor ;
if ( idProduct )
new - > idProduct = idProduct ;
if ( bcdDevice )
new - > bcdDevice = bcdDevice ;
2012-09-10 11:16:07 +04:00
else
new - > bcdDevice = cpu_to_le16 ( get_default_bcdDevice ( ) ) ;
2012-09-10 17:01:54 +04:00
if ( iSerialNumber )
new - > iSerialNumber = iSerialNumber ;
2012-09-10 17:01:55 +04:00
if ( iManufacturer )
new - > iManufacturer = iManufacturer ;
2012-09-10 17:01:56 +04:00
if ( iProduct )
new - > iProduct = iProduct ;
2012-09-10 17:01:53 +04:00
}
2012-12-24 00:10:20 +04:00
int composite_dev_prepare ( struct usb_composite_driver * composite ,
struct usb_composite_dev * cdev )
2012-09-07 11:53:17 +04:00
{
2012-12-24 00:10:20 +04:00
struct usb_gadget * gadget = cdev - > gadget ;
int ret = - ENOMEM ;
2008-06-20 04:52:58 +04:00
/* preallocate control response and buffer */
cdev - > req = usb_ep_alloc_request ( gadget - > ep0 , GFP_KERNEL ) ;
if ( ! cdev - > req )
2012-12-24 00:10:20 +04:00
return - ENOMEM ;
2012-09-10 17:01:51 +04:00
cdev - > req - > buf = kmalloc ( USB_COMP_EP0_BUFSIZ , GFP_KERNEL ) ;
2008-06-20 04:52:58 +04:00
if ( ! cdev - > req - > buf )
goto fail ;
2012-12-24 00:10:20 +04:00
ret = device_create_file ( & gadget - > dev , & dev_attr_suspended ) ;
if ( ret )
goto fail_dev ;
2008-06-20 04:52:58 +04:00
cdev - > req - > complete = composite_setup_complete ;
gadget - > ep0 - > driver_data = cdev ;
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 .
*/
2012-12-24 00:10:20 +04:00
usb_ep_autoconfig_reset ( gadget ) ;
return 0 ;
fail_dev :
kfree ( cdev - > req - > buf ) ;
fail :
usb_ep_free_request ( gadget - > ep0 , cdev - > req ) ;
cdev - > req = NULL ;
return ret ;
}
void composite_dev_cleanup ( struct usb_composite_dev * cdev )
{
2012-12-24 00:10:23 +04:00
struct usb_gadget_string_container * uc , * tmp ;
list_for_each_entry_safe ( uc , tmp , & cdev - > gstrings , list ) {
list_del ( & uc - > list ) ;
kfree ( uc ) ;
}
2012-12-24 00:10:20 +04:00
if ( cdev - > req ) {
kfree ( cdev - > req - > buf ) ;
usb_ep_free_request ( cdev - > gadget - > ep0 , cdev - > req ) ;
}
device_remove_file ( & cdev - > gadget - > dev , & dev_attr_suspended ) ;
}
static int composite_bind ( struct usb_gadget * gadget ,
struct usb_gadget_driver * gdriver )
{
struct usb_composite_dev * cdev ;
struct usb_composite_driver * composite = to_cdriver ( gdriver ) ;
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 ) ;
2012-12-24 00:10:22 +04:00
INIT_LIST_HEAD ( & cdev - > gstrings ) ;
2012-12-24 00:10:20 +04:00
status = composite_dev_prepare ( composite , cdev ) ;
if ( status )
goto fail ;
2008-06-20 04:52:58 +04:00
/* composite gadget needs to assign strings for whole device (like
* serial number ) , register function drivers , potentially update
* power state and consumption , etc
*/
2012-09-06 22:11:01 +04:00
status = composite - > bind ( cdev ) ;
2008-06-20 04:52:58 +04:00
if ( status < 0 )
goto fail ;
2012-09-10 17:01:53 +04:00
update_unchanged_dev_desc ( & cdev - > desc , composite - > dev ) ;
2010-12-17 02:52:30 +03:00
2010-08-12 19:43:46 +04:00
/* 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
INFO ( cdev , " %s ready \n " , composite - > name ) ;
return 0 ;
fail :
2012-12-24 00:09:55 +04:00
__composite_unbind ( gadget , false ) ;
2008-06-20 04:52:58 +04:00
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 ) ;
}
}
2012-09-07 11:53:17 +04:00
if ( cdev - > driver - > suspend )
cdev - > driver - > 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 " ) ;
2012-09-07 11:53:17 +04:00
if ( cdev - > driver - > resume )
cdev - > driver - > 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
2012-12-03 23:07:05 +04:00
maxpower = cdev - > config - > MaxPower ;
2010-11-29 10:17:03 +03:00
usb_gadget_vbus_draw ( gadget , maxpower ?
2012-12-03 23:07:05 +04:00
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
}
/*-------------------------------------------------------------------------*/
2012-09-07 11:53:17 +04:00
static const struct usb_gadget_driver composite_driver_template = {
2012-09-06 22:11:05 +04:00
. bind = composite_bind ,
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 .
*/
2012-09-06 22:11:04 +04:00
int usb_composite_probe ( struct usb_composite_driver * driver )
2008-06-20 04:52:58 +04:00
{
2012-09-07 11:53:17 +04:00
struct usb_gadget_driver * gadget_driver ;
if ( ! driver | | ! driver - > dev | | ! driver - > bind )
2008-06-20 04:52:58 +04:00
return - EINVAL ;
if ( ! driver - > name )
driver - > name = " composite " ;
2012-09-07 11:53:17 +04:00
driver - > gadget_driver = composite_driver_template ;
gadget_driver = & driver - > gadget_driver ;
gadget_driver - > function = ( char * ) driver - > name ;
gadget_driver - > driver . name = driver - > name ;
gadget_driver - > max_speed = driver - > max_speed ;
return usb_gadget_probe_driver ( gadget_driver ) ;
2008-06-20 04:52:58 +04:00
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_composite_probe ) ;
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
{
2012-09-07 11:53:17 +04:00
usb_gadget_unregister_driver ( & driver - > gadget_driver ) ;
2008-06-20 04:52:58 +04:00
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_composite_unregister ) ;
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 ) ;
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_composite_setup_continue ) ;
2011-05-09 14:08:06 +04:00
2012-09-10 17:01:58 +04:00
static char * composite_default_mfr ( struct usb_gadget * gadget )
{
char * mfr ;
int len ;
len = snprintf ( NULL , 0 , " %s %s with %s " , init_utsname ( ) - > sysname ,
init_utsname ( ) - > release , gadget - > name ) ;
len + + ;
mfr = kmalloc ( len , GFP_KERNEL ) ;
if ( ! mfr )
return NULL ;
snprintf ( mfr , len , " %s %s with %s " , init_utsname ( ) - > sysname ,
init_utsname ( ) - > release , gadget - > name ) ;
return mfr ;
}
2012-09-10 17:01:53 +04:00
void usb_composite_overwrite_options ( struct usb_composite_dev * cdev ,
struct usb_composite_overwrite * covr )
{
struct usb_device_descriptor * desc = & cdev - > desc ;
2012-09-10 17:01:54 +04:00
struct usb_gadget_strings * gstr = cdev - > driver - > strings [ 0 ] ;
struct usb_string * dev_str = gstr - > strings ;
2012-09-10 17:01:53 +04:00
if ( covr - > idVendor )
desc - > idVendor = cpu_to_le16 ( covr - > idVendor ) ;
if ( covr - > idProduct )
desc - > idProduct = cpu_to_le16 ( covr - > idProduct ) ;
if ( covr - > bcdDevice )
desc - > bcdDevice = cpu_to_le16 ( covr - > bcdDevice ) ;
2012-09-10 17:01:54 +04:00
if ( covr - > serial_number ) {
desc - > iSerialNumber = dev_str [ USB_GADGET_SERIAL_IDX ] . id ;
dev_str [ USB_GADGET_SERIAL_IDX ] . s = covr - > serial_number ;
}
2012-09-10 17:01:55 +04:00
if ( covr - > manufacturer ) {
desc - > iManufacturer = dev_str [ USB_GADGET_MANUFACTURER_IDX ] . id ;
dev_str [ USB_GADGET_MANUFACTURER_IDX ] . s = covr - > manufacturer ;
2012-09-10 17:01:58 +04:00
} else if ( ! strlen ( dev_str [ USB_GADGET_MANUFACTURER_IDX ] . s ) ) {
desc - > iManufacturer = dev_str [ USB_GADGET_MANUFACTURER_IDX ] . id ;
cdev - > def_manufacturer = composite_default_mfr ( cdev - > gadget ) ;
dev_str [ USB_GADGET_MANUFACTURER_IDX ] . s = cdev - > def_manufacturer ;
2012-09-10 17:01:55 +04:00
}
2012-09-10 17:01:56 +04:00
if ( covr - > product ) {
desc - > iProduct = dev_str [ USB_GADGET_PRODUCT_IDX ] . id ;
dev_str [ USB_GADGET_PRODUCT_IDX ] . s = covr - > product ;
}
2012-09-10 17:01:53 +04:00
}
2012-09-06 22:11:27 +04:00
EXPORT_SYMBOL_GPL ( usb_composite_overwrite_options ) ;
2012-09-06 22:11:28 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " David Brownell " ) ;