2010-11-12 16:29:28 +03:00
/*
* g_ffs . c - - user mode file system API for USB composite function controllers
*
* Copyright ( C ) 2010 Samsung Electronics
2012-01-13 18:05:16 +04:00
* Author : Michal Nazarewicz < mina86 @ mina86 . com >
2010-11-12 16:29:28 +03:00
*
* 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 .
*/
2010-11-17 19:09:47 +03:00
# define pr_fmt(fmt) "g_ffs: " fmt
2010-05-05 14:53:15 +04:00
# include <linux/module.h>
2013-12-03 18:15:34 +04:00
2010-05-05 14:53:15 +04:00
# if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
2013-12-03 18:15:25 +04:00
# include <linux/netdevice.h>
2010-05-05 14:53:15 +04:00
# if defined USB_ETH_RNDIS
# undef USB_ETH_RNDIS
# endif
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
# define USB_ETH_RNDIS y
# endif
2013-12-03 18:15:23 +04:00
# include "u_ecm.h"
2013-12-03 18:15:25 +04:00
# include "u_gether.h"
2010-05-05 14:53:15 +04:00
# ifdef USB_ETH_RNDIS
2013-12-03 18:15:27 +04:00
# include "u_rndis.h"
2013-05-24 12:23:02 +04:00
# include "rndis.h"
2010-05-05 14:53:15 +04:00
# endif
usb: gadget: u_ether: convert into module
u_ether.c has been #include'd by all gadgets which implement
USB Ethernet functions. In order to add configfs support,
the f_ecm.c, f_eem.c, f_ncm.c, f_subset.c, f_rndis.c need to be
converted into modules and must not be #include'd. Consequently,
the u_ether.c needs to be a module too, in a manner similar
to u_serial.c. The resulting module should not take any parameters,
so they are pushed to the current users of it, that is ether.c,
g_ffs.c, multi.c, ncm.c, nokia.c.
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
2013-05-23 11:22:03 +04:00
# include "u_ether.h"
2010-05-05 14:53:15 +04:00
2013-12-03 18:15:23 +04:00
USB_ETHERNET_MODULE_PARAMETERS ( ) ;
2010-06-25 18:29:27 +04:00
# ifdef CONFIG_USB_FUNCTIONFS_ETH
2013-12-03 18:15:27 +04:00
static int eth_bind_config ( struct usb_configuration * c ) ;
2013-12-03 18:15:23 +04:00
static struct usb_function_instance * fi_ecm ;
static struct usb_function * f_ecm ;
2013-12-03 18:15:25 +04:00
static struct usb_function_instance * fi_geth ;
static struct usb_function * f_geth ;
2010-05-05 14:53:15 +04:00
# endif
2013-12-03 18:15:27 +04:00
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
static int bind_rndis_config ( struct usb_configuration * c ) ;
static struct usb_function_instance * fi_rndis ;
static struct usb_function * f_rndis ;
# endif
2010-05-05 14:53:15 +04:00
# endif
2013-12-03 18:15:34 +04:00
# include "u_fs.h"
2010-05-05 14:53:15 +04:00
# define DRIVER_NAME "g_ffs"
# define DRIVER_DESC "USB Function Filesystem"
# define DRIVER_VERSION "24 Aug 2004"
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_AUTHOR ( " Michal Nazarewicz " ) ;
MODULE_LICENSE ( " GPL " ) ;
2010-08-12 19:43:48 +04:00
# define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */
# define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */
2010-05-05 14:53:15 +04:00
2012-05-14 17:51:52 +04:00
# define GFS_MAX_DEVS 10
2012-09-10 17:01:53 +04:00
USB_GADGET_COMPOSITE_OPTIONS ( ) ;
2010-05-05 14:53:15 +04:00
static struct usb_device_descriptor gfs_dev_desc = {
. bLength = sizeof gfs_dev_desc ,
. bDescriptorType = USB_DT_DEVICE ,
. bcdUSB = cpu_to_le16 ( 0x0200 ) ,
. bDeviceClass = USB_CLASS_PER_INTERFACE ,
2010-08-12 19:43:48 +04:00
. idVendor = cpu_to_le16 ( GFS_VENDOR_ID ) ,
. idProduct = cpu_to_le16 ( GFS_PRODUCT_ID ) ,
2010-05-05 14:53:15 +04:00
} ;
2012-05-14 17:51:52 +04:00
static char * func_names [ GFS_MAX_DEVS ] ;
static unsigned int func_num ;
2010-08-12 19:43:48 +04:00
module_param_named ( bDeviceClass , gfs_dev_desc . bDeviceClass , byte , 0644 ) ;
MODULE_PARM_DESC ( bDeviceClass , " USB Device class " ) ;
module_param_named ( bDeviceSubClass , gfs_dev_desc . bDeviceSubClass , byte , 0644 ) ;
MODULE_PARM_DESC ( bDeviceSubClass , " USB Device subclass " ) ;
module_param_named ( bDeviceProtocol , gfs_dev_desc . bDeviceProtocol , byte , 0644 ) ;
MODULE_PARM_DESC ( bDeviceProtocol , " USB Device protocol " ) ;
2012-05-14 17:51:52 +04:00
module_param_array_named ( functions , func_names , charp , & func_num , 0 ) ;
MODULE_PARM_DESC ( functions , " USB Functions list " ) ;
2010-05-05 14:53:15 +04:00
static const struct usb_descriptor_header * gfs_otg_desc [ ] = {
( const struct usb_descriptor_header * )
& ( const struct usb_otg_descriptor ) {
. bLength = sizeof ( struct usb_otg_descriptor ) ,
. bDescriptorType = USB_DT_OTG ,
2010-08-12 19:43:48 +04:00
/*
* REVISIT SRP - only hardware is possible , although
* it would not be called " OTG " . . .
*/
2010-05-05 14:53:15 +04:00
. bmAttributes = USB_OTG_SRP | USB_OTG_HNP ,
} ,
NULL
} ;
2010-11-12 16:29:28 +03:00
/* String IDs are assigned dynamically */
2010-05-05 14:53:15 +04:00
static struct usb_string gfs_strings [ ] = {
2012-09-06 22:11:21 +04:00
[ USB_GADGET_MANUFACTURER_IDX ] . s = " " ,
2012-09-10 17:01:57 +04:00
[ USB_GADGET_PRODUCT_IDX ] . s = DRIVER_DESC ,
2012-09-06 22:11:21 +04:00
[ USB_GADGET_SERIAL_IDX ] . s = " " ,
2010-05-05 14:53:15 +04:00
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
2010-06-25 18:29:27 +04:00
{ . s = " FunctionFS + RNDIS " } ,
2010-05-05 14:53:15 +04:00
# endif
# ifdef CONFIG_USB_FUNCTIONFS_ETH
2010-06-25 18:29:27 +04:00
{ . s = " FunctionFS + ECM " } ,
2010-05-05 14:53:15 +04:00
# endif
# ifdef CONFIG_USB_FUNCTIONFS_GENERIC
2010-06-25 18:29:27 +04:00
{ . s = " FunctionFS " } ,
2010-05-05 14:53:15 +04:00
# endif
{ } /* end of list */
} ;
static struct usb_gadget_strings * gfs_dev_strings [ ] = {
& ( struct usb_gadget_strings ) {
. language = 0x0409 , /* en-us */
. strings = gfs_strings ,
} ,
NULL ,
} ;
2010-06-25 18:29:27 +04:00
struct gfs_configuration {
struct usb_configuration c ;
2013-12-03 18:15:27 +04:00
int ( * eth ) ( struct usb_configuration * c ) ;
2013-12-03 18:15:34 +04:00
int num ;
2010-06-25 18:29:27 +04:00
} gfs_configurations [ ] = {
2010-05-05 14:53:15 +04:00
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
2010-06-25 18:29:27 +04:00
{
2013-12-03 18:15:27 +04:00
. eth = bind_rndis_config ,
2010-06-25 18:29:27 +04:00
} ,
2010-05-05 14:53:15 +04:00
# endif
# ifdef CONFIG_USB_FUNCTIONFS_ETH
2010-06-25 18:29:27 +04:00
{
. eth = eth_bind_config ,
} ,
2010-05-05 14:53:15 +04:00
# endif
# ifdef CONFIG_USB_FUNCTIONFS_GENERIC
2010-06-25 18:29:27 +04:00
{
} ,
2010-05-05 14:53:15 +04:00
# endif
2010-06-25 18:29:27 +04:00
} ;
2010-05-05 14:53:15 +04:00
2013-12-03 18:15:34 +04:00
static void * functionfs_acquire_dev ( struct ffs_dev * dev ) ;
static void functionfs_release_dev ( struct ffs_dev * dev ) ;
2013-12-03 18:15:32 +04:00
static int functionfs_ready_callback ( struct ffs_data * ffs ) ;
static void functionfs_closed_callback ( struct ffs_data * ffs ) ;
2010-05-05 14:53:15 +04:00
static int gfs_bind ( struct usb_composite_dev * cdev ) ;
static int gfs_unbind ( struct usb_composite_dev * cdev ) ;
2010-06-25 18:29:27 +04:00
static int gfs_do_config ( struct usb_configuration * c ) ;
2010-05-05 14:53:15 +04:00
2013-12-03 18:15:34 +04:00
2012-09-06 22:11:03 +04:00
static __refdata struct usb_composite_driver gfs_driver = {
2010-08-12 19:43:48 +04:00
. name = DRIVER_NAME ,
2010-05-05 14:53:15 +04:00
. dev = & gfs_dev_desc ,
. strings = gfs_dev_strings ,
2011-06-29 17:41:49 +04:00
. max_speed = USB_SPEED_HIGH ,
2012-09-06 22:11:04 +04:00
. bind = gfs_bind ,
2010-05-05 14:53:15 +04:00
. unbind = gfs_unbind ,
} ;
2012-05-14 17:51:52 +04:00
static unsigned int missing_funcs ;
static bool gfs_registered ;
static bool gfs_single_func ;
2013-12-03 18:15:34 +04:00
static struct usb_function_instance * * fi_ffs ;
static struct usb_function * * f_ffs [ ] = {
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
NULL ,
# endif
# ifdef CONFIG_USB_FUNCTIONFS_ETH
NULL ,
# endif
# ifdef CONFIG_USB_FUNCTIONFS_GENERIC
NULL ,
# endif
} ;
# define N_CONF ARRAY_SIZE(f_ffs)
2010-05-05 14:53:15 +04:00
2012-03-12 15:55:42 +04:00
static int __init gfs_init ( void )
2010-05-05 14:53:15 +04:00
{
2013-12-03 18:15:34 +04:00
struct f_fs_opts * opts ;
2012-05-14 17:51:52 +04:00
int i ;
2013-12-03 18:15:32 +04:00
int ret = 0 ;
2012-05-14 17:51:52 +04:00
2010-05-05 14:53:15 +04:00
ENTER ( ) ;
2013-12-03 18:15:32 +04:00
if ( func_num < 2 ) {
2012-05-14 17:51:52 +04:00
gfs_single_func = true ;
func_num = 1 ;
}
2013-12-03 18:15:34 +04:00
/*
* Allocate in one chunk for easier maintenance
*/
f_ffs [ 0 ] = kcalloc ( func_num * N_CONF , sizeof ( * f_ffs ) , GFP_KERNEL ) ;
if ( ! f_ffs [ 0 ] ) {
ret = - ENOMEM ;
goto no_func ;
}
for ( i = 1 ; i < N_CONF ; + + i )
f_ffs [ i ] = f_ffs [ 0 ] + i * func_num ;
fi_ffs = kcalloc ( func_num , sizeof ( * fi_ffs ) , GFP_KERNEL ) ;
if ( ! fi_ffs ) {
ret = - ENOMEM ;
goto no_func ;
}
2012-05-14 17:51:52 +04:00
2013-12-03 18:15:32 +04:00
for ( i = 0 ; i < func_num ; i + + ) {
2013-12-03 18:15:34 +04:00
fi_ffs [ i ] = usb_get_function_instance ( " ffs " ) ;
if ( IS_ERR ( fi_ffs [ i ] ) ) {
ret = PTR_ERR ( fi_ffs [ i ] ) ;
2013-12-03 18:15:32 +04:00
- - i ;
goto no_dev ;
}
2013-12-03 18:15:34 +04:00
opts = to_f_fs_opts ( fi_ffs [ i ] ) ;
2013-12-03 18:15:32 +04:00
if ( gfs_single_func )
2013-12-03 18:15:34 +04:00
ret = ffs_single_dev ( opts - > dev ) ;
2013-12-03 18:15:32 +04:00
else
2013-12-03 18:15:34 +04:00
ret = ffs_name_dev ( opts - > dev , func_names [ i ] ) ;
2013-12-03 18:15:32 +04:00
if ( ret )
goto no_dev ;
2013-12-03 18:15:34 +04:00
opts - > dev - > ffs_ready_callback = functionfs_ready_callback ;
opts - > dev - > ffs_closed_callback = functionfs_closed_callback ;
opts - > dev - > ffs_acquire_dev_callback = functionfs_acquire_dev ;
opts - > dev - > ffs_release_dev_callback = functionfs_release_dev ;
opts - > no_configfs = true ;
2013-12-03 18:15:32 +04:00
}
2012-05-14 17:51:52 +04:00
missing_funcs = func_num ;
2013-12-03 18:15:32 +04:00
return 0 ;
no_dev :
while ( i > = 0 )
2013-12-03 18:15:34 +04:00
usb_put_function_instance ( fi_ffs [ i - - ] ) ;
kfree ( fi_ffs ) ;
no_func :
kfree ( f_ffs [ 0 ] ) ;
2013-12-03 18:15:32 +04:00
return ret ;
2010-05-05 14:53:15 +04:00
}
module_init ( gfs_init ) ;
2012-03-12 15:55:42 +04:00
static void __exit gfs_exit ( void )
2010-05-05 14:53:15 +04:00
{
2013-12-03 18:15:32 +04:00
int i ;
2010-05-05 14:53:15 +04:00
ENTER ( ) ;
2012-05-14 17:51:52 +04:00
if ( gfs_registered )
2010-05-05 14:53:15 +04:00
usb_composite_unregister ( & gfs_driver ) ;
2012-05-14 17:51:52 +04:00
gfs_registered = false ;
2010-05-05 14:53:15 +04:00
2013-12-03 18:15:34 +04:00
kfree ( f_ffs [ 0 ] ) ;
2013-12-03 18:15:32 +04:00
for ( i = 0 ; i < func_num ; i + + )
2013-12-03 18:15:34 +04:00
usb_put_function_instance ( fi_ffs [ i ] ) ;
kfree ( fi_ffs ) ;
2010-05-05 14:53:15 +04:00
}
module_exit ( gfs_exit ) ;
2013-12-03 18:15:34 +04:00
static void * functionfs_acquire_dev ( struct ffs_dev * dev )
{
if ( ! try_module_get ( THIS_MODULE ) )
2014-05-21 16:05:35 +04:00
return ERR_PTR ( - ENOENT ) ;
2013-12-03 18:15:34 +04:00
return 0 ;
}
static void functionfs_release_dev ( struct ffs_dev * dev )
{
module_put ( THIS_MODULE ) ;
}
2013-12-03 18:15:32 +04:00
/*
* The caller of this function takes ffs_lock
*/
2010-05-05 14:53:15 +04:00
static int functionfs_ready_callback ( struct ffs_data * ffs )
{
2013-12-03 18:15:32 +04:00
int ret = 0 ;
2012-05-14 17:51:52 +04:00
2013-12-03 18:15:32 +04:00
if ( - - missing_funcs )
return 0 ;
2010-05-05 14:53:15 +04:00
2013-12-03 18:15:32 +04:00
if ( gfs_registered )
return - EBUSY ;
2012-05-14 17:51:52 +04:00
gfs_registered = true ;
2010-05-05 14:53:15 +04:00
2012-09-06 22:11:04 +04:00
ret = usb_composite_probe ( & gfs_driver ) ;
2010-05-05 14:53:15 +04:00
if ( unlikely ( ret < 0 ) )
2012-05-14 17:51:52 +04:00
gfs_registered = false ;
2013-12-03 18:15:32 +04:00
2010-05-05 14:53:15 +04:00
return ret ;
}
2013-12-03 18:15:32 +04:00
/*
* The caller of this function takes ffs_lock
*/
2010-05-05 14:53:15 +04:00
static void functionfs_closed_callback ( struct ffs_data * ffs )
{
2012-05-14 17:51:52 +04:00
missing_funcs + + ;
if ( gfs_registered )
2010-05-05 14:53:15 +04:00
usb_composite_unregister ( & gfs_driver ) ;
2012-05-14 17:51:52 +04:00
gfs_registered = false ;
}
/*
2013-12-03 18:15:32 +04:00
* It is assumed that gfs_bind is called from a context where ffs_lock is held
2012-05-14 17:51:52 +04:00
*/
2010-05-05 14:53:15 +04:00
static int gfs_bind ( struct usb_composite_dev * cdev )
{
2013-12-03 18:15:27 +04:00
# if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
2013-12-03 18:15:25 +04:00
struct net_device * net ;
# endif
2010-06-25 18:29:27 +04:00
int ret , i ;
2010-05-05 14:53:15 +04:00
ENTER ( ) ;
2012-05-14 17:51:52 +04:00
if ( missing_funcs )
2010-05-05 14:53:15 +04:00
return - ENODEV ;
2013-12-03 18:15:23 +04:00
# if defined CONFIG_USB_FUNCTIONFS_ETH
if ( can_support_ecm ( cdev - > gadget ) ) {
struct f_ecm_opts * ecm_opts ;
fi_ecm = usb_get_function_instance ( " ecm " ) ;
if ( IS_ERR ( fi_ecm ) )
return PTR_ERR ( fi_ecm ) ;
ecm_opts = container_of ( fi_ecm , struct f_ecm_opts , func_inst ) ;
2013-12-03 18:15:25 +04:00
net = ecm_opts - > net ;
2013-12-03 18:15:23 +04:00
} else {
2013-12-03 18:15:25 +04:00
struct f_gether_opts * geth_opts ;
fi_geth = usb_get_function_instance ( " geth " ) ;
if ( IS_ERR ( fi_geth ) )
return PTR_ERR ( fi_geth ) ;
geth_opts = container_of ( fi_geth , struct f_gether_opts ,
func_inst ) ;
net = geth_opts - > net ;
2013-12-03 18:15:23 +04:00
}
2013-12-03 18:15:27 +04:00
# endif
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
{
struct f_rndis_opts * rndis_opts ;
fi_rndis = usb_get_function_instance ( " rndis " ) ;
if ( IS_ERR ( fi_rndis ) ) {
ret = PTR_ERR ( fi_rndis ) ;
goto error ;
}
rndis_opts = container_of ( fi_rndis , struct f_rndis_opts ,
func_inst ) ;
# ifndef CONFIG_USB_FUNCTIONFS_ETH
net = rndis_opts - > net ;
# endif
}
# endif
2013-12-03 18:15:25 +04:00
2013-12-03 18:15:27 +04:00
# if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
gether_set_qmult ( net , qmult ) ;
2013-12-03 18:15:25 +04:00
if ( ! gether_set_host_addr ( net , host_addr ) )
pr_info ( " using host ethernet address: %s " , host_addr ) ;
if ( ! gether_set_dev_addr ( net , dev_addr ) )
pr_info ( " using self ethernet address: %s " , dev_addr ) ;
2012-12-24 00:10:12 +04:00
# endif
2013-12-03 18:15:23 +04:00
# if defined CONFIG_USB_FUNCTIONFS_RNDIS && defined CONFIG_USB_FUNCTIONFS_ETH
2013-12-03 18:15:25 +04:00
gether_set_gadget ( net , cdev - > gadget ) ;
ret = gether_register_netdev ( net ) ;
if ( ret )
2013-12-03 18:15:27 +04:00
goto error_rndis ;
2013-12-03 18:15:25 +04:00
2013-12-03 18:15:23 +04:00
if ( can_support_ecm ( cdev - > gadget ) ) {
struct f_ecm_opts * ecm_opts ;
ecm_opts = container_of ( fi_ecm , struct f_ecm_opts , func_inst ) ;
ecm_opts - > bound = true ;
2013-12-03 18:15:25 +04:00
} else {
struct f_gether_opts * geth_opts ;
geth_opts = container_of ( fi_geth , struct f_gether_opts ,
func_inst ) ;
geth_opts - > bound = true ;
2012-12-24 00:10:12 +04:00
}
2013-12-03 18:15:27 +04:00
rndis_borrow_net ( fi_rndis , net ) ;
2013-12-03 18:15:23 +04:00
# endif
2010-05-05 14:53:15 +04:00
2013-12-03 18:15:34 +04:00
/* TODO: gstrings_attach? */
2010-06-25 18:29:27 +04:00
ret = usb_string_ids_tab ( cdev , gfs_strings ) ;
2010-05-05 14:53:15 +04:00
if ( unlikely ( ret < 0 ) )
2013-12-03 18:15:27 +04:00
goto error_rndis ;
2012-09-10 17:01:57 +04:00
gfs_dev_desc . iProduct = gfs_strings [ USB_GADGET_PRODUCT_IDX ] . id ;
2010-05-05 14:53:15 +04:00
2010-06-25 18:29:27 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( gfs_configurations ) ; + + i ) {
struct gfs_configuration * c = gfs_configurations + i ;
2012-09-06 22:11:21 +04:00
int sid = USB_GADGET_FIRST_AVAIL_IDX + i ;
2010-05-05 14:53:15 +04:00
2012-09-06 22:11:21 +04:00
c - > c . label = gfs_strings [ sid ] . s ;
c - > c . iConfiguration = gfs_strings [ sid ] . id ;
2010-06-25 18:29:27 +04:00
c - > c . bConfigurationValue = 1 + i ;
c - > c . bmAttributes = USB_CONFIG_ATT_SELFPOWER ;
2010-05-05 14:53:15 +04:00
2013-12-03 18:15:34 +04:00
c - > num = i ;
2010-08-12 19:43:55 +04:00
ret = usb_add_config ( cdev , & c - > c , gfs_do_config ) ;
2010-06-25 18:29:27 +04:00
if ( unlikely ( ret < 0 ) )
goto error_unbind ;
}
2012-09-10 17:01:53 +04:00
usb_composite_overwrite_options ( cdev , & coverwrite ) ;
2010-05-05 14:53:15 +04:00
return 0 ;
2013-12-03 18:15:34 +04:00
/* TODO */
2010-05-05 14:53:15 +04:00
error_unbind :
2013-12-03 18:15:27 +04:00
error_rndis :
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
usb_put_function_instance ( fi_rndis ) ;
2010-05-05 14:53:15 +04:00
error :
2013-12-03 18:15:27 +04:00
# endif
2013-12-03 18:15:23 +04:00
# if defined CONFIG_USB_FUNCTIONFS_ETH
if ( can_support_ecm ( cdev - > gadget ) )
usb_put_function_instance ( fi_ecm ) ;
else
2013-12-03 18:15:25 +04:00
usb_put_function_instance ( fi_geth ) ;
2013-12-03 18:15:23 +04:00
# endif
2010-05-05 14:53:15 +04:00
return ret ;
}
2012-05-14 17:51:52 +04:00
/*
2013-12-03 18:15:32 +04:00
* It is assumed that gfs_unbind is called from a context where ffs_lock is held
2012-05-14 17:51:52 +04:00
*/
2010-05-05 14:53:15 +04:00
static int gfs_unbind ( struct usb_composite_dev * cdev )
{
2012-05-14 17:51:52 +04:00
int i ;
2010-05-05 14:53:15 +04:00
ENTER ( ) ;
2013-12-03 18:15:23 +04:00
2013-12-03 18:15:27 +04:00
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
usb_put_function ( f_rndis ) ;
usb_put_function_instance ( fi_rndis ) ;
# endif
2013-12-03 18:15:23 +04:00
# if defined CONFIG_USB_FUNCTIONFS_ETH
if ( can_support_ecm ( cdev - > gadget ) ) {
usb_put_function ( f_ecm ) ;
usb_put_function_instance ( fi_ecm ) ;
} else {
2013-12-03 18:15:25 +04:00
usb_put_function ( f_geth ) ;
usb_put_function_instance ( fi_geth ) ;
2013-12-03 18:15:23 +04:00
}
# endif
2013-12-03 18:15:34 +04:00
for ( i = 0 ; i < N_CONF * func_num ; + + i )
usb_put_function ( * ( f_ffs [ 0 ] + i ) ) ;
2010-05-05 14:53:15 +04:00
return 0 ;
}
2012-05-14 17:51:52 +04:00
/*
* It is assumed that gfs_do_config is called from a context where
2013-12-03 18:15:32 +04:00
* ffs_lock is held
2012-05-14 17:51:52 +04:00
*/
2010-06-25 18:29:27 +04:00
static int gfs_do_config ( struct usb_configuration * c )
2010-05-05 14:53:15 +04:00
{
2010-06-25 18:29:27 +04:00
struct gfs_configuration * gc =
container_of ( c , struct gfs_configuration , c ) ;
2012-05-14 17:51:52 +04:00
int i ;
2010-05-05 14:53:15 +04:00
int ret ;
2012-05-14 17:51:52 +04:00
if ( missing_funcs )
2010-05-05 14:53:15 +04:00
return - ENODEV ;
if ( gadget_is_otg ( c - > cdev - > gadget ) ) {
c - > descriptors = gfs_otg_desc ;
c - > bmAttributes | = USB_CONFIG_ATT_WAKEUP ;
}
2010-06-25 18:29:27 +04:00
if ( gc - > eth ) {
2013-12-03 18:15:27 +04:00
ret = gc - > eth ( c ) ;
2010-05-05 14:53:15 +04:00
if ( unlikely ( ret < 0 ) )
return ret ;
}
2012-05-14 17:51:52 +04:00
for ( i = 0 ; i < func_num ; i + + ) {
2013-12-03 18:15:34 +04:00
f_ffs [ gc - > num ] [ i ] = usb_get_function ( fi_ffs [ i ] ) ;
if ( IS_ERR ( f_ffs [ gc - > num ] [ i ] ) ) {
ret = PTR_ERR ( f_ffs [ gc - > num ] [ i ] ) ;
goto error ;
}
ret = usb_add_function ( c , f_ffs [ gc - > num ] [ i ] ) ;
if ( ret < 0 ) {
usb_put_function ( f_ffs [ gc - > num ] [ i ] ) ;
goto error ;
}
2012-05-14 17:51:52 +04:00
}
2010-05-05 14:53:15 +04:00
2010-08-12 19:43:48 +04:00
/*
* After previous do_configs there may be some invalid
2010-06-14 12:43:34 +04:00
* pointers in c - > interface array . This happens every time
* a user space function with fewer interfaces than a user
* space function that was run before the new one is run . The
* compasit ' s set_config ( ) assumes that if there is no more
* then MAX_CONFIG_INTERFACES interfaces in a configuration
* then there is a NULL pointer after the last interface in
2010-08-12 19:43:48 +04:00
* c - > interface array . We need to make sure this is true .
*/
2010-06-14 12:43:34 +04:00
if ( c - > next_interface_id < ARRAY_SIZE ( c - > interface ) )
c - > interface [ c - > next_interface_id ] = NULL ;
2010-05-05 14:53:15 +04:00
return 0 ;
2013-12-03 18:15:34 +04:00
error :
while ( - - i > = 0 ) {
if ( ! IS_ERR ( f_ffs [ gc - > num ] [ i ] ) )
usb_remove_function ( c , f_ffs [ gc - > num ] [ i ] ) ;
usb_put_function ( f_ffs [ gc - > num ] [ i ] ) ;
}
return ret ;
2010-05-05 14:53:15 +04:00
}
# ifdef CONFIG_USB_FUNCTIONFS_ETH
2010-08-12 19:43:48 +04:00
2013-12-03 18:15:27 +04:00
static int eth_bind_config ( struct usb_configuration * c )
2010-05-05 14:53:15 +04:00
{
2013-12-03 18:15:23 +04:00
int status = 0 ;
if ( can_support_ecm ( c - > cdev - > gadget ) ) {
f_ecm = usb_get_function ( fi_ecm ) ;
if ( IS_ERR ( f_ecm ) )
return PTR_ERR ( f_ecm ) ;
status = usb_add_function ( c , f_ecm ) ;
if ( status < 0 )
usb_put_function ( f_ecm ) ;
} else {
2013-12-03 18:15:25 +04:00
f_geth = usb_get_function ( fi_geth ) ;
if ( IS_ERR ( f_geth ) )
return PTR_ERR ( f_geth ) ;
status = usb_add_function ( c , f_geth ) ;
if ( status < 0 )
usb_put_function ( f_geth ) ;
2013-12-03 18:15:23 +04:00
}
return status ;
2010-05-05 14:53:15 +04:00
}
2010-08-12 19:43:48 +04:00
2010-05-05 14:53:15 +04:00
# endif
2013-12-03 18:15:27 +04:00
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
static int bind_rndis_config ( struct usb_configuration * c )
{
int status = 0 ;
f_rndis = usb_get_function ( fi_rndis ) ;
if ( IS_ERR ( f_rndis ) )
return PTR_ERR ( f_rndis ) ;
status = usb_add_function ( c , f_rndis ) ;
if ( status < 0 )
usb_put_function ( f_rndis ) ;
return status ;
}
# endif