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/utsname.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 .
*/
# include "composite.c"
# include "usbstring.c"
# include "config.c"
# include "epautoconf.c"
# include "u_serial.c"
# include "f_acm.c"
# include "f_ecm.c"
# include "f_obex.c"
# include "f_serial.c"
# include "f_phonet.c"
# include "u_ether.c"
/*-------------------------------------------------------------------------*/
# define NOKIA_VENDOR_ID 0x0421 /* Nokia */
# define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */
/* string IDs are assigned dynamically */
# define STRING_MANUFACTURER_IDX 0
# define STRING_PRODUCT_IDX 1
# define STRING_DESCRIPTION_IDX 2
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 [ ] = {
[ STRING_MANUFACTURER_IDX ] . s = manufacturer_nokia ,
[ STRING_PRODUCT_IDX ] . s = NOKIA_LONG_NAME ,
[ 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 ) ,
/* .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 ] ;
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 " ) ;
status = obex_bind_config ( c , 0 ) ;
if ( status )
printk ( KERN_DEBUG " could not bind obex config %d \n " , 0 ) ;
status = obex_bind_config ( c , 1 ) ;
if ( status )
printk ( KERN_DEBUG " could not bind obex config %d \n " , 0 ) ;
status = acm_bind_config ( c , 2 ) ;
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 ,
. bMaxPower = 250 , /* 500mA */
} ;
static struct usb_configuration nokia_config_100ma_driver = {
. label = " Self Powered " ,
. bConfigurationValue = 2 ,
/* .iConfiguration = DYNAMIC */
. bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER ,
. bMaxPower = 50 , /* 100 mA */
} ;
static int __init nokia_bind ( struct usb_composite_dev * cdev )
{
int gcnum ;
struct usb_gadget * gadget = cdev - > gadget ;
int status ;
status = gphonet_setup ( cdev - > gadget ) ;
if ( status < 0 )
goto err_phonet ;
status = gserial_setup ( cdev - > gadget , 3 ) ;
if ( status < 0 )
goto err_serial ;
status = gether_setup ( cdev - > gadget , hostaddr ) ;
if ( status < 0 )
goto err_ether ;
status = usb_string_id ( cdev ) ;
if ( status < 0 )
goto err_usb ;
strings_dev [ STRING_MANUFACTURER_IDX ] . id = status ;
device_desc . iManufacturer = status ;
status = usb_string_id ( cdev ) ;
if ( status < 0 )
goto err_usb ;
strings_dev [ STRING_PRODUCT_IDX ] . id = status ;
device_desc . iProduct = status ;
/* config description */
status = usb_string_id ( cdev ) ;
if ( status < 0 )
goto err_usb ;
strings_dev [ STRING_DESCRIPTION_IDX ] . id = status ;
nokia_config_500ma_driver . iConfiguration = status ;
nokia_config_100ma_driver . iConfiguration = status ;
/* set up other descriptors */
gcnum = usb_gadget_controller_number ( gadget ) ;
if ( gcnum > = 0 )
device_desc . bcdDevice = cpu_to_le16 ( NOKIA_VERSION_NUM ) ;
else {
/* this should only work with hw that supports altsettings
* and several endpoints , anything else , panic .
*/
pr_err ( " nokia_bind: controller '%s' not recognized \n " ,
gadget - > name ) ;
goto err_usb ;
}
/* finaly 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 ;
dev_info ( & gadget - > dev , " %s \n " , NOKIA_LONG_NAME ) ;
return 0 ;
err_usb :
gether_cleanup ( ) ;
err_ether :
gserial_cleanup ( ) ;
err_serial :
gphonet_cleanup ( ) ;
err_phonet :
return status ;
}
static int __exit nokia_unbind ( struct usb_composite_dev * cdev )
{
gphonet_cleanup ( ) ;
gserial_cleanup ( ) ;
gether_cleanup ( ) ;
return 0 ;
}
static struct usb_composite_driver nokia_driver = {
. name = " g_nokia " ,
. dev = & device_desc ,
. strings = dev_strings ,
. unbind = __exit_p ( nokia_unbind ) ,
} ;
static int __init nokia_init ( void )
{
2010-08-12 19:43:54 +04:00
return usb_composite_probe ( & nokia_driver , nokia_bind ) ;
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 ) ;