2010-01-05 16:10:13 +02:00
/*
* nokia . c - - Nokia Composite Gadget Driver
*
* Copyright ( C ) 2008 - 2010 Nokia Corporation
* Contact : Felipe Balbi < felipe . balbi @ nokia . com >
*
* This gadget driver borrows from serial . c which is :
*
* Copyright ( C ) 2003 Al Borchers ( alborchers @ steinerpoint . com )
* Copyright ( C ) 2008 by David Brownell
* Copyright ( C ) 2008 by Nokia Corporation
*
* This software is distributed under the terms of the GNU General
* Public License ( " GPL " ) as published by the Free Software Foundation ,
* version 2 of that License .
*/
# include <linux/kernel.h>
2013-05-23 10:51:08 +02:00
# include <linux/module.h>
2010-01-05 16:10:13 +02:00
# include <linux/device.h>
# include "u_serial.h"
# include "u_ether.h"
# include "u_phonet.h"
2013-05-23 10:51:14 +02:00
# include "u_ecm.h"
2015-06-08 08:20:05 +02:00
# include "f_mass_storage.h"
2010-01-05 16:10:13 +02:00
/* Defines */
# define NOKIA_VERSION_NUM 0x0211
# define NOKIA_LONG_NAME "N900 (PC-Suite Mode)"
2012-09-10 15:01:53 +02:00
USB_GADGET_COMPOSITE_OPTIONS ( ) ;
2010-01-05 16:10:13 +02:00
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 09:22:03 +02:00
USB_ETHERNET_MODULE_PARAMETERS ( ) ;
2015-06-08 08:20:05 +02:00
static struct fsg_module_parameters fsg_mod_data = {
. stall = 0 ,
. luns = 2 ,
. removable_count = 2 ,
. removable = { 1 , 1 , } ,
} ;
# ifdef CONFIG_USB_GADGET_DEBUG_FILES
static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS ;
# else
/*
* Number of buffers we will use .
* 2 is usually enough for good buffering pipeline
*/
# define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
# endif /* CONFIG_USB_DEBUG */
FSG_MODULE_PARAMETERS ( /* no prefix */ , fsg_mod_data ) ;
2010-01-05 16:10:13 +02:00
# define NOKIA_VENDOR_ID 0x0421 /* Nokia */
# define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */
/* string IDs are assigned dynamically */
2012-09-06 20:11:21 +02:00
# define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX
2010-01-05 16:10:13 +02:00
static char manufacturer_nokia [ ] = " Nokia " ;
static const char product_nokia [ ] = NOKIA_LONG_NAME ;
static const char description_nokia [ ] = " PC-Suite Configuration " ;
static struct usb_string strings_dev [ ] = {
2012-09-06 20:11:21 +02:00
[ USB_GADGET_MANUFACTURER_IDX ] . s = manufacturer_nokia ,
[ USB_GADGET_PRODUCT_IDX ] . s = NOKIA_LONG_NAME ,
[ USB_GADGET_SERIAL_IDX ] . s = " " ,
2010-01-05 16:10:13 +02:00
[ STRING_DESCRIPTION_IDX ] . s = description_nokia ,
{ } /* end of list */
} ;
static struct usb_gadget_strings stringtab_dev = {
. language = 0x0409 , /* en-us */
. strings = strings_dev ,
} ;
static struct usb_gadget_strings * dev_strings [ ] = {
& stringtab_dev ,
NULL ,
} ;
static struct usb_device_descriptor device_desc = {
. bLength = USB_DT_DEVICE_SIZE ,
. bDescriptorType = USB_DT_DEVICE ,
2015-10-20 18:33:13 +02:00
/* .bcdUSB = DYNAMIC */
2010-01-05 16:10:13 +02:00
. bDeviceClass = USB_CLASS_COMM ,
2015-06-06 07:02:53 +05:30
. idVendor = cpu_to_le16 ( NOKIA_VENDOR_ID ) ,
. idProduct = cpu_to_le16 ( NOKIA_PRODUCT_ID ) ,
2012-09-10 09:16:07 +02:00
. bcdDevice = cpu_to_le16 ( NOKIA_VERSION_NUM ) ,
2010-01-05 16:10:13 +02:00
/* .iManufacturer = DYNAMIC */
/* .iProduct = DYNAMIC */
. bNumConfigurations = 1 ,
} ;
/*-------------------------------------------------------------------------*/
/* Module */
MODULE_DESCRIPTION ( " Nokia composite gadget driver for N900 " ) ;
MODULE_AUTHOR ( " Felipe Balbi " ) ;
MODULE_LICENSE ( " GPL " ) ;
/*-------------------------------------------------------------------------*/
2013-01-25 14:09:17 +01:00
static struct usb_function * f_acm_cfg1 ;
static struct usb_function * f_acm_cfg2 ;
2013-05-23 10:51:14 +02:00
static struct usb_function * f_ecm_cfg1 ;
static struct usb_function * f_ecm_cfg2 ;
2013-05-23 10:51:08 +02:00
static struct usb_function * f_obex1_cfg1 ;
static struct usb_function * f_obex2_cfg1 ;
static struct usb_function * f_obex1_cfg2 ;
static struct usb_function * f_obex2_cfg2 ;
2013-05-23 10:51:12 +02:00
static struct usb_function * f_phonet_cfg1 ;
static struct usb_function * f_phonet_cfg2 ;
2015-06-08 08:20:05 +02:00
static struct usb_function * f_msg_cfg1 ;
static struct usb_function * f_msg_cfg2 ;
2013-05-23 10:51:10 +02:00
2010-01-05 16:10:13 +02:00
2013-01-25 14:09:17 +01:00
static struct usb_configuration nokia_config_500ma_driver = {
. label = " Bus Powered " ,
. bConfigurationValue = 1 ,
/* .iConfiguration = DYNAMIC */
. bmAttributes = USB_CONFIG_ATT_ONE ,
. MaxPower = 500 ,
} ;
static struct usb_configuration nokia_config_100ma_driver = {
. label = " Self Powered " ,
. bConfigurationValue = 2 ,
/* .iConfiguration = DYNAMIC */
. bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER ,
. MaxPower = 100 ,
} ;
static struct usb_function_instance * fi_acm ;
2013-05-23 10:51:14 +02:00
static struct usb_function_instance * fi_ecm ;
2013-05-23 10:51:08 +02:00
static struct usb_function_instance * fi_obex1 ;
static struct usb_function_instance * fi_obex2 ;
2013-05-23 10:51:12 +02:00
static struct usb_function_instance * fi_phonet ;
2015-06-08 08:20:05 +02:00
static struct usb_function_instance * fi_msg ;
2013-01-25 14:09:17 +01:00
2015-04-11 00:14:21 +02:00
static int nokia_bind_config ( struct usb_configuration * c )
2010-01-05 16:10:13 +02:00
{
2013-01-25 14:09:17 +01:00
struct usb_function * f_acm ;
2013-05-23 10:51:12 +02:00
struct usb_function * f_phonet = NULL ;
2013-05-23 10:51:08 +02:00
struct usb_function * f_obex1 = NULL ;
2013-05-23 10:51:14 +02:00
struct usb_function * f_ecm ;
2013-05-23 10:51:08 +02:00
struct usb_function * f_obex2 = NULL ;
2015-06-08 08:20:05 +02:00
struct usb_function * f_msg ;
2010-01-05 16:10:13 +02:00
int status = 0 ;
2013-12-13 14:46:40 +01:00
int obex1_stat = - 1 ;
int obex2_stat = - 1 ;
int phonet_stat = - 1 ;
2010-01-05 16:10:13 +02:00
2013-05-23 10:51:12 +02:00
if ( ! IS_ERR ( fi_phonet ) ) {
f_phonet = usb_get_function ( fi_phonet ) ;
if ( IS_ERR ( f_phonet ) )
pr_debug ( " could not get phonet function \n " ) ;
}
2010-01-05 16:10:13 +02:00
2013-05-23 10:51:08 +02:00
if ( ! IS_ERR ( fi_obex1 ) ) {
f_obex1 = usb_get_function ( fi_obex1 ) ;
if ( IS_ERR ( f_obex1 ) )
pr_debug ( " could not get obex function 0 \n " ) ;
}
2010-01-05 16:10:13 +02:00
2013-05-23 10:51:08 +02:00
if ( ! IS_ERR ( fi_obex2 ) ) {
f_obex2 = usb_get_function ( fi_obex2 ) ;
if ( IS_ERR ( f_obex2 ) )
pr_debug ( " could not get obex function 1 \n " ) ;
}
2010-01-05 16:10:13 +02:00
2013-01-25 14:09:17 +01:00
f_acm = usb_get_function ( fi_acm ) ;
2013-05-23 10:51:08 +02:00
if ( IS_ERR ( f_acm ) ) {
status = PTR_ERR ( f_acm ) ;
goto err_get_acm ;
}
2013-05-23 10:51:14 +02:00
f_ecm = usb_get_function ( fi_ecm ) ;
if ( IS_ERR ( f_ecm ) ) {
status = PTR_ERR ( f_ecm ) ;
goto err_get_ecm ;
}
2015-06-08 08:20:05 +02:00
f_msg = usb_get_function ( fi_msg ) ;
if ( IS_ERR ( f_msg ) ) {
status = PTR_ERR ( f_msg ) ;
goto err_get_msg ;
}
2013-05-23 10:51:12 +02:00
if ( ! IS_ERR_OR_NULL ( f_phonet ) ) {
phonet_stat = usb_add_function ( c , f_phonet ) ;
if ( phonet_stat )
pr_debug ( " could not add phonet function \n " ) ;
}
2013-05-23 10:51:08 +02:00
if ( ! IS_ERR_OR_NULL ( f_obex1 ) ) {
obex1_stat = usb_add_function ( c , f_obex1 ) ;
if ( obex1_stat )
pr_debug ( " could not add obex function 0 \n " ) ;
}
if ( ! IS_ERR_OR_NULL ( f_obex2 ) ) {
obex2_stat = usb_add_function ( c , f_obex2 ) ;
if ( obex2_stat )
pr_debug ( " could not add obex function 1 \n " ) ;
}
2013-01-25 14:09:17 +01:00
status = usb_add_function ( c , f_acm ) ;
2010-01-05 16:10:13 +02:00
if ( status )
2013-01-25 14:09:17 +01:00
goto err_conf ;
2010-01-05 16:10:13 +02:00
2013-05-23 10:51:14 +02:00
status = usb_add_function ( c , f_ecm ) ;
2013-01-25 14:09:17 +01:00
if ( status ) {
pr_debug ( " could not bind ecm config %d \n " , status ) ;
goto err_ecm ;
}
2015-06-08 08:20:05 +02:00
status = usb_add_function ( c , f_msg ) ;
if ( status )
goto err_msg ;
2013-05-23 10:51:08 +02:00
if ( c = = & nokia_config_500ma_driver ) {
2013-01-25 14:09:17 +01:00
f_acm_cfg1 = f_acm ;
2013-05-23 10:51:14 +02:00
f_ecm_cfg1 = f_ecm ;
2013-05-23 10:51:12 +02:00
f_phonet_cfg1 = f_phonet ;
2013-05-23 10:51:08 +02:00
f_obex1_cfg1 = f_obex1 ;
f_obex2_cfg1 = f_obex2 ;
2015-06-08 08:20:05 +02:00
f_msg_cfg1 = f_msg ;
2013-05-23 10:51:08 +02:00
} else {
2013-01-25 14:09:17 +01:00
f_acm_cfg2 = f_acm ;
2013-05-23 10:51:14 +02:00
f_ecm_cfg2 = f_ecm ;
2013-05-23 10:51:12 +02:00
f_phonet_cfg2 = f_phonet ;
2013-05-23 10:51:08 +02:00
f_obex1_cfg2 = f_obex1 ;
f_obex2_cfg2 = f_obex2 ;
2015-06-08 08:20:05 +02:00
f_msg_cfg2 = f_msg ;
2013-05-23 10:51:08 +02:00
}
2010-01-05 16:10:13 +02:00
return status ;
2015-06-08 08:20:05 +02:00
err_msg :
usb_remove_function ( c , f_ecm ) ;
2013-01-25 14:09:17 +01:00
err_ecm :
usb_remove_function ( c , f_acm ) ;
err_conf :
2013-05-23 10:51:08 +02:00
if ( ! obex2_stat )
usb_remove_function ( c , f_obex2 ) ;
if ( ! obex1_stat )
usb_remove_function ( c , f_obex1 ) ;
2013-05-23 10:51:12 +02:00
if ( ! phonet_stat )
usb_remove_function ( c , f_phonet ) ;
2015-06-08 08:20:05 +02:00
usb_put_function ( f_msg ) ;
err_get_msg :
2013-05-23 10:51:14 +02:00
usb_put_function ( f_ecm ) ;
err_get_ecm :
2013-01-25 14:09:17 +01:00
usb_put_function ( f_acm ) ;
2013-05-23 10:51:08 +02:00
err_get_acm :
if ( ! IS_ERR_OR_NULL ( f_obex2 ) )
usb_put_function ( f_obex2 ) ;
if ( ! IS_ERR_OR_NULL ( f_obex1 ) )
usb_put_function ( f_obex1 ) ;
2013-05-23 10:51:12 +02:00
if ( ! IS_ERR_OR_NULL ( f_phonet ) )
usb_put_function ( f_phonet ) ;
2013-01-25 14:09:17 +01:00
return status ;
2010-01-05 16:10:13 +02:00
}
2015-04-11 00:14:21 +02:00
static int nokia_bind ( struct usb_composite_dev * cdev )
2010-01-05 16:10:13 +02:00
{
struct usb_gadget * gadget = cdev - > gadget ;
2015-06-08 08:20:05 +02:00
struct fsg_opts * fsg_opts ;
struct fsg_config fsg_config ;
2010-01-05 16:10:13 +02:00
int status ;
2012-09-06 20:11:16 +02:00
status = usb_string_ids_tab ( cdev , strings_dev ) ;
2010-01-05 16:10:13 +02:00
if ( status < 0 )
goto err_usb ;
2012-09-06 20:11:21 +02:00
device_desc . iManufacturer = strings_dev [ USB_GADGET_MANUFACTURER_IDX ] . id ;
device_desc . iProduct = strings_dev [ USB_GADGET_PRODUCT_IDX ] . id ;
2012-09-06 20:11:16 +02:00
status = strings_dev [ STRING_DESCRIPTION_IDX ] . id ;
2010-01-05 16:10:13 +02:00
nokia_config_500ma_driver . iConfiguration = status ;
nokia_config_100ma_driver . iConfiguration = status ;
2015-07-28 07:20:03 +02:00
if ( ! gadget_is_altset_supported ( gadget ) ) {
2013-05-23 10:51:14 +02:00
status = - ENODEV ;
2010-01-05 16:10:13 +02:00
goto err_usb ;
2013-05-23 10:51:14 +02:00
}
2010-01-05 16:10:13 +02:00
2013-05-23 10:51:12 +02:00
fi_phonet = usb_get_function_instance ( " phonet " ) ;
if ( IS_ERR ( fi_phonet ) )
pr_debug ( " could not find phonet function \n " ) ;
2013-05-23 10:51:08 +02:00
fi_obex1 = usb_get_function_instance ( " obex " ) ;
if ( IS_ERR ( fi_obex1 ) )
pr_debug ( " could not find obex function 1 \n " ) ;
fi_obex2 = usb_get_function_instance ( " obex " ) ;
if ( IS_ERR ( fi_obex2 ) )
pr_debug ( " could not find obex function 2 \n " ) ;
2013-01-25 14:09:17 +01:00
fi_acm = usb_get_function_instance ( " acm " ) ;
2013-05-23 10:51:14 +02:00
if ( IS_ERR ( fi_acm ) ) {
status = PTR_ERR ( fi_acm ) ;
2013-05-23 10:51:08 +02:00
goto err_obex2_inst ;
2013-05-23 10:51:14 +02:00
}
fi_ecm = usb_get_function_instance ( " ecm " ) ;
if ( IS_ERR ( fi_ecm ) ) {
status = PTR_ERR ( fi_ecm ) ;
goto err_acm_inst ;
}
2013-01-25 14:09:17 +01:00
2015-06-08 08:20:05 +02:00
fi_msg = usb_get_function_instance ( " mass_storage " ) ;
if ( IS_ERR ( fi_msg ) ) {
status = PTR_ERR ( fi_msg ) ;
goto err_ecm_inst ;
}
/* set up mass storage function */
fsg_config_from_params ( & fsg_config , & fsg_mod_data , fsg_num_buffers ) ;
fsg_config . vendor_name = " Nokia " ;
fsg_config . product_name = " N900 " ;
fsg_opts = fsg_opts_from_func_inst ( fi_msg ) ;
fsg_opts - > no_configfs = true ;
status = fsg_common_set_num_buffers ( fsg_opts - > common , fsg_num_buffers ) ;
if ( status )
goto err_msg_inst ;
status = fsg_common_set_cdev ( fsg_opts - > common , cdev , fsg_config . can_stall ) ;
if ( status )
2015-07-31 13:46:07 +02:00
goto err_msg_buf ;
2015-06-08 08:20:05 +02:00
fsg_common_set_sysfs ( fsg_opts - > common , true ) ;
status = fsg_common_create_luns ( fsg_opts - > common , & fsg_config ) ;
if ( status )
2015-07-31 13:46:07 +02:00
goto err_msg_buf ;
2015-06-08 08:20:05 +02:00
fsg_common_set_inquiry_string ( fsg_opts - > common , fsg_config . vendor_name ,
fsg_config . product_name ) ;
2011-03-30 22:57:33 -03:00
/* finally register the configuration */
2010-08-12 17:43:55 +02:00
status = usb_add_config ( cdev , & nokia_config_500ma_driver ,
nokia_bind_config ) ;
2010-01-05 16:10:13 +02:00
if ( status < 0 )
2015-07-31 13:46:07 +02:00
goto err_msg_luns ;
2010-01-05 16:10:13 +02:00
2010-08-12 17:43:55 +02:00
status = usb_add_config ( cdev , & nokia_config_100ma_driver ,
nokia_bind_config ) ;
2010-01-05 16:10:13 +02:00
if ( status < 0 )
2013-01-25 14:09:17 +01:00
goto err_put_cfg1 ;
2010-01-05 16:10:13 +02:00
2012-09-10 15:01:53 +02:00
usb_composite_overwrite_options ( cdev , & coverwrite ) ;
2010-01-05 16:10:13 +02:00
dev_info ( & gadget - > dev , " %s \n " , NOKIA_LONG_NAME ) ;
return 0 ;
2013-01-25 14:09:17 +01:00
err_put_cfg1 :
usb_put_function ( f_acm_cfg1 ) ;
2013-05-23 10:51:08 +02:00
if ( ! IS_ERR_OR_NULL ( f_obex1_cfg1 ) )
usb_put_function ( f_obex1_cfg1 ) ;
if ( ! IS_ERR_OR_NULL ( f_obex2_cfg1 ) )
usb_put_function ( f_obex2_cfg1 ) ;
2013-05-23 10:51:12 +02:00
if ( ! IS_ERR_OR_NULL ( f_phonet_cfg1 ) )
usb_put_function ( f_phonet_cfg1 ) ;
2013-05-23 10:51:14 +02:00
usb_put_function ( f_ecm_cfg1 ) ;
2015-07-31 13:46:07 +02:00
err_msg_luns :
2015-06-08 08:20:05 +02:00
fsg_common_remove_luns ( fsg_opts - > common ) ;
err_msg_buf :
fsg_common_free_buffers ( fsg_opts - > common ) ;
err_msg_inst :
usb_put_function_instance ( fi_msg ) ;
2013-05-23 10:51:14 +02:00
err_ecm_inst :
usb_put_function_instance ( fi_ecm ) ;
2013-01-25 14:09:17 +01:00
err_acm_inst :
usb_put_function_instance ( fi_acm ) ;
2013-05-23 10:51:08 +02:00
err_obex2_inst :
if ( ! IS_ERR ( fi_obex2 ) )
usb_put_function_instance ( fi_obex2 ) ;
if ( ! IS_ERR ( fi_obex1 ) )
usb_put_function_instance ( fi_obex1 ) ;
2013-05-23 10:51:12 +02:00
if ( ! IS_ERR ( fi_phonet ) )
usb_put_function_instance ( fi_phonet ) ;
2010-01-05 16:10:13 +02:00
err_usb :
return status ;
}
2015-04-11 00:14:21 +02:00
static int nokia_unbind ( struct usb_composite_dev * cdev )
2010-01-05 16:10:13 +02:00
{
2013-05-23 10:51:08 +02:00
if ( ! IS_ERR_OR_NULL ( f_obex1_cfg2 ) )
usb_put_function ( f_obex1_cfg2 ) ;
if ( ! IS_ERR_OR_NULL ( f_obex2_cfg2 ) )
usb_put_function ( f_obex2_cfg2 ) ;
if ( ! IS_ERR_OR_NULL ( f_obex1_cfg1 ) )
usb_put_function ( f_obex1_cfg1 ) ;
if ( ! IS_ERR_OR_NULL ( f_obex2_cfg1 ) )
usb_put_function ( f_obex2_cfg1 ) ;
2013-05-23 10:51:12 +02:00
if ( ! IS_ERR_OR_NULL ( f_phonet_cfg1 ) )
usb_put_function ( f_phonet_cfg1 ) ;
if ( ! IS_ERR_OR_NULL ( f_phonet_cfg2 ) )
usb_put_function ( f_phonet_cfg2 ) ;
2013-01-25 14:09:17 +01:00
usb_put_function ( f_acm_cfg1 ) ;
usb_put_function ( f_acm_cfg2 ) ;
2013-05-23 10:51:14 +02:00
usb_put_function ( f_ecm_cfg1 ) ;
usb_put_function ( f_ecm_cfg2 ) ;
2015-06-08 08:20:05 +02:00
usb_put_function ( f_msg_cfg1 ) ;
usb_put_function ( f_msg_cfg2 ) ;
2013-05-23 10:51:12 +02:00
2015-06-08 08:20:05 +02:00
usb_put_function_instance ( fi_msg ) ;
2013-05-23 10:51:14 +02:00
usb_put_function_instance ( fi_ecm ) ;
2013-05-23 10:51:08 +02:00
if ( ! IS_ERR ( fi_obex2 ) )
usb_put_function_instance ( fi_obex2 ) ;
2013-05-23 10:51:12 +02:00
if ( ! IS_ERR ( fi_obex1 ) )
usb_put_function_instance ( fi_obex1 ) ;
if ( ! IS_ERR ( fi_phonet ) )
usb_put_function_instance ( fi_phonet ) ;
2013-01-25 14:09:17 +01:00
usb_put_function_instance ( fi_acm ) ;
2012-12-23 21:10:06 +01:00
2010-01-05 16:10:13 +02:00
return 0 ;
}
2015-04-11 00:14:21 +02:00
static struct usb_composite_driver nokia_driver = {
2010-01-05 16:10:13 +02:00
. name = " g_nokia " ,
. dev = & device_desc ,
. strings = dev_strings ,
2011-06-29 16:41:49 +03:00
. max_speed = USB_SPEED_HIGH ,
2012-09-06 20:11:04 +02:00
. bind = nokia_bind ,
2015-04-11 00:14:21 +02:00
. unbind = nokia_unbind ,
2010-01-05 16:10:13 +02:00
} ;
2014-07-09 18:09:56 +02:00
module_usb_composite_driver ( nokia_driver ) ;