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 .
*/
2012-12-24 00:10:07 +04:00
# define USB_FACM_INCLUDED
2010-01-05 17:10:13 +03:00
# include "f_acm.c"
# include "f_ecm.c"
# include "f_obex.c"
# include "f_serial.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 " ) ;
/*-------------------------------------------------------------------------*/
static u8 hostaddr [ ETH_ALEN ] ;
2012-12-24 00:10:06 +04:00
enum {
TTY_PORT_OBEX0 ,
TTY_PORT_OBEX1 ,
TTY_PORT_ACM ,
TTY_PORTS_MAX ,
} ;
static unsigned char tty_lines [ TTY_PORTS_MAX ] ;
2010-01-05 17:10:13 +03:00
static int __init nokia_bind_config ( struct usb_configuration * c )
{
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 ) ;
2012-12-24 00:10:06 +04:00
status = acm_bind_config ( c , tty_lines [ TTY_PORT_ACM ] ) ;
2010-01-05 17:10:13 +03:00
if ( status )
printk ( KERN_DEBUG " could not bind acm config \n " ) ;
status = ecm_bind_config ( c , hostaddr ) ;
if ( status )
printk ( KERN_DEBUG " could not bind ecm config \n " ) ;
return status ;
}
static struct usb_configuration nokia_config_500ma_driver = {
. label = " Bus Powered " ,
. bConfigurationValue = 1 ,
/* .iConfiguration = DYNAMIC */
. bmAttributes = USB_CONFIG_ATT_ONE ,
2012-12-03 23:07:05 +04:00
. MaxPower = 500 ,
2010-01-05 17:10:13 +03:00
} ;
static struct usb_configuration nokia_config_100ma_driver = {
. label = " Self Powered " ,
. bConfigurationValue = 2 ,
/* .iConfiguration = DYNAMIC */
. bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER ,
2012-12-03 23:07:05 +04:00
. MaxPower = 100 ,
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
status = gether_setup ( cdev - > gadget , hostaddr ) ;
if ( status < 0 )
goto err_ether ;
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 ;
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 )
goto err_usb ;
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 )
goto err_usb ;
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 ;
err_usb :
gether_cleanup ( ) ;
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 ;
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 ] ) ;
2010-01-05 17:10:13 +03:00
gether_cleanup ( ) ;
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 ) ;