2010-01-05 17:10:13 +03: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>
# include <linux/device.h>
# include "u_serial.h"
# include "u_ether.h"
# include "u_phonet.h"
# include "gadget_chips.h"
/* Defines */
# define NOKIA_VERSION_NUM 0x0211
# define NOKIA_LONG_NAME "N900 (PC-Suite Mode)"
/*-------------------------------------------------------------------------*/
/*
* Kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module . So for now we won ' t use
* separate compilation . . . ensuring init / exit sections work to shrink
* the runtime footprint , and giving us at least some parts of what
* a " gcc --combine ... part1.c part2.c part3.c ... " build would .
*/
2013-03-21 18:33:42 +04:00
# define USBF_OBEX_INCLUDED
2013-04-03 22:01:44 +04:00
# include "f_ecm.c"
2010-01-05 17:10:13 +03:00
# include "f_obex.c"
# include "f_phonet.c"
# include "u_ether.c"
/*-------------------------------------------------------------------------*/
2012-09-10 17:01:53 +04:00
USB_GADGET_COMPOSITE_OPTIONS ( ) ;
2010-01-05 17:10:13 +03:00
# define NOKIA_VENDOR_ID 0x0421 /* Nokia */
# define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */
/* string IDs are assigned dynamically */
2012-09-06 22:11:21 +04:00
# define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX
2010-01-05 17:10:13 +03: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 22:11:21 +04:00
[ USB_GADGET_MANUFACTURER_IDX ] . s = manufacturer_nokia ,
[ USB_GADGET_PRODUCT_IDX ] . s = NOKIA_LONG_NAME ,
[ USB_GADGET_SERIAL_IDX ] . s = " " ,
2010-01-05 17:10:13 +03: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 ,
. bcdUSB = __constant_cpu_to_le16 ( 0x0200 ) ,
. bDeviceClass = USB_CLASS_COMM ,
. idVendor = __constant_cpu_to_le16 ( NOKIA_VENDOR_ID ) ,
. idProduct = __constant_cpu_to_le16 ( NOKIA_PRODUCT_ID ) ,
2012-09-10 11:16:07 +04:00
. bcdDevice = cpu_to_le16 ( NOKIA_VERSION_NUM ) ,
2010-01-05 17:10:13 +03: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 17:09:17 +04:00
static struct usb_function * f_acm_cfg1 ;
static struct usb_function * f_acm_cfg2 ;
2010-01-05 17:10:13 +03:00
static u8 hostaddr [ ETH_ALEN ] ;
2012-12-24 00:10:12 +04:00
static struct eth_dev * the_dev ;
2010-01-05 17:10:13 +03:00
2012-12-24 00:10:06 +04:00
enum {
TTY_PORT_OBEX0 ,
TTY_PORT_OBEX1 ,
TTY_PORTS_MAX ,
} ;
static unsigned char tty_lines [ TTY_PORTS_MAX ] ;
2013-01-25 17:09:17 +04: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 ;
2010-01-05 17:10:13 +03:00
static int __init nokia_bind_config ( struct usb_configuration * c )
{
2013-01-25 17:09:17 +04:00
struct usb_function * f_acm ;
2010-01-05 17:10:13 +03:00
int status = 0 ;
status = phonet_bind_config ( c ) ;
if ( status )
printk ( KERN_DEBUG " could not bind phonet config \n " ) ;
2012-12-24 00:10:06 +04:00
status = obex_bind_config ( c , tty_lines [ TTY_PORT_OBEX0 ] ) ;
2010-01-05 17:10:13 +03:00
if ( status )
printk ( KERN_DEBUG " could not bind obex config %d \n " , 0 ) ;
2012-12-24 00:10:06 +04:00
status = obex_bind_config ( c , tty_lines [ TTY_PORT_OBEX1 ] ) ;
2010-01-05 17:10:13 +03:00
if ( status )
printk ( KERN_DEBUG " could not bind obex config %d \n " , 0 ) ;
2013-01-25 17:09:17 +04:00
f_acm = usb_get_function ( fi_acm ) ;
if ( IS_ERR ( f_acm ) )
return PTR_ERR ( f_acm ) ;
status = usb_add_function ( c , f_acm ) ;
2010-01-05 17:10:13 +03:00
if ( status )
2013-01-25 17:09:17 +04:00
goto err_conf ;
2010-01-05 17:10:13 +03:00
2012-12-24 00:10:12 +04:00
status = ecm_bind_config ( c , hostaddr , the_dev ) ;
2013-01-25 17:09:17 +04:00
if ( status ) {
pr_debug ( " could not bind ecm config %d \n " , status ) ;
goto err_ecm ;
}
if ( c = = & nokia_config_500ma_driver )
f_acm_cfg1 = f_acm ;
else
f_acm_cfg2 = f_acm ;
2010-01-05 17:10:13 +03:00
return status ;
2013-01-25 17:09:17 +04:00
err_ecm :
usb_remove_function ( c , f_acm ) ;
err_conf :
usb_put_function ( f_acm ) ;
return status ;
2010-01-05 17:10:13 +03:00
}
static int __init nokia_bind ( struct usb_composite_dev * cdev )
{
struct usb_gadget * gadget = cdev - > gadget ;
int status ;
2012-12-24 00:10:06 +04:00
int cur_line ;
2010-01-05 17:10:13 +03:00
status = gphonet_setup ( cdev - > gadget ) ;
if ( status < 0 )
goto err_phonet ;
2012-12-24 00:10:06 +04:00
for ( cur_line = 0 ; cur_line < TTY_PORTS_MAX ; cur_line + + ) {
status = gserial_alloc_line ( & tty_lines [ cur_line ] ) ;
if ( status )
goto err_ether ;
}
2010-01-05 17:10:13 +03:00
2012-12-24 00:10:12 +04:00
the_dev = gether_setup ( cdev - > gadget , hostaddr ) ;
if ( IS_ERR ( the_dev ) ) {
status = PTR_ERR ( the_dev ) ;
2010-01-05 17:10:13 +03:00
goto err_ether ;
2012-12-24 00:10:12 +04:00
}
2010-01-05 17:10:13 +03:00
2012-09-06 22:11:16 +04:00
status = usb_string_ids_tab ( cdev , strings_dev ) ;
2010-01-05 17:10:13 +03:00
if ( status < 0 )
goto err_usb ;
2012-09-06 22:11:21 +04:00
device_desc . iManufacturer = strings_dev [ USB_GADGET_MANUFACTURER_IDX ] . id ;
device_desc . iProduct = strings_dev [ USB_GADGET_PRODUCT_IDX ] . id ;
2012-09-06 22:11:16 +04:00
status = strings_dev [ STRING_DESCRIPTION_IDX ] . id ;
2010-01-05 17:10:13 +03:00
nokia_config_500ma_driver . iConfiguration = status ;
nokia_config_100ma_driver . iConfiguration = status ;
2012-09-10 11:16:07 +04:00
if ( ! gadget_supports_altsettings ( gadget ) )
2010-01-05 17:10:13 +03:00
goto err_usb ;
2013-01-25 17:09:17 +04:00
fi_acm = usb_get_function_instance ( " acm " ) ;
if ( IS_ERR ( fi_acm ) )
goto err_usb ;
2011-03-31 05:57:33 +04:00
/* finally register the configuration */
2010-08-12 19:43:55 +04:00
status = usb_add_config ( cdev , & nokia_config_500ma_driver ,
nokia_bind_config ) ;
2010-01-05 17:10:13 +03:00
if ( status < 0 )
2013-01-25 17:09:17 +04:00
goto err_acm_inst ;
2010-01-05 17:10:13 +03:00
2010-08-12 19:43:55 +04:00
status = usb_add_config ( cdev , & nokia_config_100ma_driver ,
nokia_bind_config ) ;
2010-01-05 17:10:13 +03:00
if ( status < 0 )
2013-01-25 17:09:17 +04:00
goto err_put_cfg1 ;
2010-01-05 17:10:13 +03:00
2012-09-10 17:01:53 +04:00
usb_composite_overwrite_options ( cdev , & coverwrite ) ;
2010-01-05 17:10:13 +03:00
dev_info ( & gadget - > dev , " %s \n " , NOKIA_LONG_NAME ) ;
return 0 ;
2013-01-25 17:09:17 +04:00
err_put_cfg1 :
usb_put_function ( f_acm_cfg1 ) ;
err_acm_inst :
usb_put_function_instance ( fi_acm ) ;
2010-01-05 17:10:13 +03:00
err_usb :
2012-12-24 00:10:12 +04:00
gether_cleanup ( the_dev ) ;
2010-01-05 17:10:13 +03:00
err_ether :
2012-12-24 00:10:06 +04:00
cur_line - - ;
while ( cur_line > = 0 )
gserial_free_line ( tty_lines [ cur_line - - ] ) ;
2010-01-05 17:10:13 +03:00
gphonet_cleanup ( ) ;
err_phonet :
return status ;
}
static int __exit nokia_unbind ( struct usb_composite_dev * cdev )
{
2012-12-24 00:10:06 +04:00
int i ;
2013-01-25 17:09:17 +04:00
usb_put_function ( f_acm_cfg1 ) ;
usb_put_function ( f_acm_cfg2 ) ;
usb_put_function_instance ( fi_acm ) ;
2010-01-05 17:10:13 +03:00
gphonet_cleanup ( ) ;
2012-12-24 00:10:06 +04:00
for ( i = 0 ; i < TTY_PORTS_MAX ; i + + )
gserial_free_line ( tty_lines [ i ] ) ;
2012-12-24 00:10:12 +04:00
gether_cleanup ( the_dev ) ;
2010-01-05 17:10:13 +03:00
return 0 ;
}
2012-09-06 22:11:03 +04:00
static __refdata struct usb_composite_driver nokia_driver = {
2010-01-05 17:10:13 +03:00
. name = " g_nokia " ,
. dev = & device_desc ,
. strings = dev_strings ,
2011-06-29 17:41:49 +04:00
. max_speed = USB_SPEED_HIGH ,
2012-09-06 22:11:04 +04:00
. bind = nokia_bind ,
2010-01-05 17:10:13 +03:00
. unbind = __exit_p ( nokia_unbind ) ,
} ;
static int __init nokia_init ( void )
{
2012-09-06 22:11:04 +04:00
return usb_composite_probe ( & nokia_driver ) ;
2010-01-05 17:10:13 +03:00
}
module_init ( nokia_init ) ;
static void __exit nokia_cleanup ( void )
{
usb_composite_unregister ( & nokia_driver ) ;
}
module_exit ( nokia_cleanup ) ;