2005-04-16 15:20:36 -07:00
/*
2008-06-19 17:52:07 -07:00
* serial . c - - USB gadget serial driver
2005-04-16 15:20:36 -07:00
*
2008-06-19 17:52:07 -07:00
* Copyright ( C ) 2003 Al Borchers ( alborchers @ steinerpoint . com )
* Copyright ( C ) 2008 by David Brownell
2008-06-19 18:19:03 -07:00
* Copyright ( C ) 2008 by Nokia Corporation
2005-04-16 15:20:36 -07:00
*
* This software is distributed under the terms of the GNU General
* Public License ( " GPL " ) as published by the Free Software Foundation ,
* either version 2 of that License or ( at your option ) any later version .
*/
# include <linux/kernel.h>
# include <linux/device.h>
2013-03-21 09:22:30 +01:00
# include <linux/module.h>
2005-04-16 15:20:36 -07:00
# include <linux/tty.h>
# include <linux/tty_flip.h>
2008-06-19 17:52:07 -07:00
# include "u_serial.h"
2005-04-16 15:20:36 -07:00
# include "gadget_chips.h"
/* Defines */
2008-06-19 18:19:03 -07:00
# define GS_VERSION_STR "v2.4"
# define GS_VERSION_NUM 0x2400
2005-04-16 15:20:36 -07:00
# define GS_LONG_NAME "Gadget Serial"
2008-06-19 17:52:07 -07:00
# define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR
2008-08-18 17:41:02 -07:00
/*-------------------------------------------------------------------------*/
2012-09-10 15:01:53 +02:00
USB_GADGET_COMPOSITE_OPTIONS ( ) ;
2008-08-18 17:41:02 -07:00
2005-04-16 15:20:36 -07:00
/* Thanks to NetChip Technologies for donating this product ID.
2008-06-19 18:19:03 -07:00
*
* DO NOT REUSE THESE IDs with a protocol - incompatible driver ! ! Ever ! !
* Instead : allocate your own , using normal USB - IF procedures .
*/
2005-04-16 15:20:36 -07:00
# define GS_VENDOR_ID 0x0525 /* NetChip */
# define GS_PRODUCT_ID 0xa4a6 /* Linux-USB Serial Gadget */
# define GS_CDC_PRODUCT_ID 0xa4a7 /* ... as CDC-ACM */
2008-08-18 17:39:30 -07:00
# define GS_CDC_OBEX_PRODUCT_ID 0xa4a9 /* ... as CDC-OBEX */
2005-04-16 15:20:36 -07:00
2008-06-19 18:19:03 -07:00
/* string IDs are assigned dynamically */
2005-04-16 15:20:36 -07:00
2012-09-06 20:11:21 +02:00
# define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX
2008-06-19 17:52:07 -07:00
2008-06-19 18:19:03 -07:00
static struct usb_string strings_dev [ ] = {
2012-09-10 15:01:58 +02:00
[ USB_GADGET_MANUFACTURER_IDX ] . s = " " ,
2012-09-06 20:11:21 +02:00
[ USB_GADGET_PRODUCT_IDX ] . s = GS_VERSION_NAME ,
[ USB_GADGET_SERIAL_IDX ] . s = " " ,
2008-06-19 18:19:03 -07:00
[ STRING_DESCRIPTION_IDX ] . s = NULL /* updated; f(use_acm) */ ,
2005-04-16 15:20:36 -07:00
{ } /* end of list */
} ;
2008-06-19 18:19:03 -07:00
static struct usb_gadget_strings stringtab_dev = {
. language = 0x0409 , /* en-us */
. strings = strings_dev ,
2005-04-16 15:20:36 -07:00
} ;
2008-06-19 18:19:03 -07:00
static struct usb_gadget_strings * dev_strings [ ] = {
& stringtab_dev ,
NULL ,
} ;
static struct usb_device_descriptor device_desc = {
2005-04-16 15:20:36 -07:00
. bLength = USB_DT_DEVICE_SIZE ,
. bDescriptorType = USB_DT_DEVICE ,
2009-02-11 14:11:36 -08:00
. bcdUSB = cpu_to_le16 ( 0x0200 ) ,
2008-06-19 18:19:03 -07:00
/* .bDeviceClass = f(use_acm) */
2005-04-16 15:20:36 -07:00
. bDeviceSubClass = 0 ,
. bDeviceProtocol = 0 ,
2008-06-19 18:19:03 -07:00
/* .bMaxPacketSize0 = f(hardware) */
2009-02-11 14:11:36 -08:00
. idVendor = cpu_to_le16 ( GS_VENDOR_ID ) ,
2008-06-19 18:19:03 -07:00
/* .idProduct = f(use_acm) */
2012-09-10 19:06:44 +02:00
. bcdDevice = cpu_to_le16 ( GS_VERSION_NUM ) ,
2008-06-19 18:19:03 -07:00
/* .iManufacturer = DYNAMIC */
/* .iProduct = DYNAMIC */
. bNumConfigurations = 1 ,
2005-04-16 15:20:36 -07:00
} ;
2008-06-19 18:19:03 -07:00
static struct usb_otg_descriptor otg_descriptor = {
. bLength = sizeof otg_descriptor ,
2005-04-16 15:20:36 -07:00
. bDescriptorType = USB_DT_OTG ,
2008-06-19 18:19:03 -07:00
/* REVISIT SRP-only hardware is possible, although
* it would not be called " OTG " . . .
*/
. bmAttributes = USB_OTG_SRP | USB_OTG_HNP ,
2008-06-19 17:52:07 -07:00
} ;
2008-06-19 18:19:03 -07:00
static const struct usb_descriptor_header * otg_desc [ ] = {
( struct usb_descriptor_header * ) & otg_descriptor ,
2008-06-19 17:52:07 -07:00
NULL ,
} ;
2005-04-16 15:20:36 -07:00
2008-06-19 17:52:07 -07:00
/*-------------------------------------------------------------------------*/
2005-04-16 15:20:36 -07:00
2008-06-19 17:52:07 -07:00
/* Module */
MODULE_DESCRIPTION ( GS_VERSION_NAME ) ;
MODULE_AUTHOR ( " Al Borchers " ) ;
MODULE_AUTHOR ( " David Brownell " ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-04-16 15:20:36 -07:00
2012-01-13 09:32:20 +10:30
static bool use_acm = true ;
2008-06-19 18:19:03 -07:00
module_param ( use_acm , bool , 0 ) ;
MODULE_PARM_DESC ( use_acm , " Use CDC ACM, default=yes " ) ;
2005-04-16 15:20:36 -07:00
2012-01-13 09:32:20 +10:30
static bool use_obex = false ;
2008-08-18 17:39:30 -07:00
module_param ( use_obex , bool , 0 ) ;
MODULE_PARM_DESC ( use_obex , " Use CDC OBEX, default=no " ) ;
2008-06-19 18:19:03 -07:00
static unsigned n_ports = 1 ;
module_param ( n_ports , uint , 0 ) ;
MODULE_PARM_DESC ( n_ports , " number of ports to create, default=1 " ) ;
2008-05-07 16:00:36 -07:00
2008-06-19 18:19:03 -07:00
/*-------------------------------------------------------------------------*/
2012-12-23 21:10:03 +01:00
2008-06-19 18:19:03 -07:00
static struct usb_configuration serial_config_driver = {
/* .label = f(use_acm) */
/* .bConfigurationValue = f(use_acm) */
/* .iConfiguration = DYNAMIC */
. bmAttributes = USB_CONFIG_ATT_SELFPOWER ,
} ;
2012-12-23 21:10:07 +01:00
static struct usb_function_instance * fi_serial [ MAX_U_SERIAL_PORTS ] ;
static struct usb_function * f_serial [ MAX_U_SERIAL_PORTS ] ;
static int serial_register_ports ( struct usb_composite_dev * cdev ,
struct usb_configuration * c , const char * f_name )
2012-12-23 21:10:06 +01:00
{
int i ;
2012-12-23 21:10:07 +01:00
int ret ;
ret = usb_add_config_only ( cdev , c ) ;
if ( ret )
goto out ;
for ( i = 0 ; i < n_ports ; i + + ) {
fi_serial [ i ] = usb_get_function_instance ( f_name ) ;
if ( IS_ERR ( fi_serial [ i ] ) ) {
ret = PTR_ERR ( fi_serial [ i ] ) ;
goto fail ;
}
f_serial [ i ] = usb_get_function ( fi_serial [ i ] ) ;
if ( IS_ERR ( f_serial [ i ] ) ) {
ret = PTR_ERR ( f_serial [ i ] ) ;
goto err_get_func ;
}
ret = usb_add_function ( c , f_serial [ i ] ) ;
if ( ret )
goto err_add_func ;
}
2012-12-23 21:10:06 +01:00
return 0 ;
2012-12-23 21:10:07 +01:00
err_add_func :
usb_put_function ( f_serial [ i ] ) ;
err_get_func :
usb_put_function_instance ( fi_serial [ i ] ) ;
fail :
i - - ;
while ( i > = 0 ) {
usb_remove_function ( c , f_serial [ i ] ) ;
usb_put_function ( f_serial [ i ] ) ;
usb_put_function_instance ( fi_serial [ i ] ) ;
i - - ;
}
out :
return ret ;
2012-12-23 21:10:06 +01:00
}
2010-08-12 17:43:52 +02:00
static int __init gs_bind ( struct usb_composite_dev * cdev )
2005-04-16 15:20:36 -07:00
{
2008-06-19 18:19:03 -07:00
int status ;
2008-06-19 17:52:07 -07:00
2008-06-19 18:19:03 -07:00
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue .
2005-07-13 15:18:30 -07:00
*/
2005-04-16 15:20:36 -07:00
2012-09-06 20:11:16 +02:00
status = usb_string_ids_tab ( cdev , strings_dev ) ;
2008-06-19 18:19:03 -07:00
if ( status < 0 )
goto fail ;
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 ;
2008-06-19 18:19:03 -07:00
serial_config_driver . iConfiguration = status ;
2005-04-16 15:20:36 -07:00
2008-06-19 18:19:03 -07:00
if ( gadget_is_otg ( cdev - > gadget ) ) {
serial_config_driver . descriptors = otg_desc ;
serial_config_driver . bmAttributes | = USB_CONFIG_ATT_WAKEUP ;
2005-04-16 15:20:36 -07:00
}
2008-05-07 16:00:36 -07:00
2008-06-19 18:19:03 -07:00
/* register our configuration */
2012-12-23 21:10:07 +01:00
if ( use_acm ) {
status = serial_register_ports ( cdev , & serial_config_driver ,
" acm " ) ;
usb_ep_autoconfig_reset ( cdev - > gadget ) ;
} else if ( use_obex )
2013-03-21 09:22:30 +01:00
status = serial_register_ports ( cdev , & serial_config_driver ,
" obex " ) ;
2013-03-14 16:02:12 +01:00
else {
status = serial_register_ports ( cdev , & serial_config_driver ,
" gser " ) ;
}
2008-06-19 18:19:03 -07:00
if ( status < 0 )
goto fail ;
2005-04-16 15:20:36 -07:00
2012-09-10 15:01:53 +02:00
usb_composite_overwrite_options ( cdev , & coverwrite ) ;
2008-06-19 18:19:03 -07:00
INFO ( cdev , " %s \n " , GS_VERSION_NAME ) ;
2005-04-16 15:20:36 -07:00
2008-06-19 18:19:03 -07:00
return 0 ;
2005-04-16 15:20:36 -07:00
2008-06-19 18:19:03 -07:00
fail :
return status ;
2005-04-16 15:20:36 -07:00
}
2012-12-23 21:10:07 +01:00
static int gs_unbind ( struct usb_composite_dev * cdev )
{
int i ;
for ( i = 0 ; i < n_ports ; i + + ) {
usb_put_function ( f_serial [ i ] ) ;
usb_put_function_instance ( fi_serial [ i ] ) ;
}
return 0 ;
}
2012-09-06 20:11:03 +02:00
static __refdata struct usb_composite_driver gserial_driver = {
2008-06-19 18:19:03 -07:00
. name = " g_serial " ,
. dev = & device_desc ,
. strings = dev_strings ,
2012-02-06 18:46:36 +01:00
. max_speed = USB_SPEED_SUPER ,
2012-09-06 20:11:04 +02:00
. bind = gs_bind ,
2012-12-23 21:10:06 +01:00
. unbind = gs_unbind ,
2008-05-07 16:00:36 -07:00
} ;
2008-06-19 18:19:03 -07:00
static int __init init ( void )
2005-04-16 15:20:36 -07:00
{
2008-06-19 18:19:03 -07:00
/* We *could* export two configs; that'd be much cleaner...
* but neither of these product IDs was defined that way .
2008-04-18 17:37:49 -07:00
*/
2005-04-16 15:20:36 -07:00
if ( use_acm ) {
2008-06-19 18:19:03 -07:00
serial_config_driver . label = " CDC ACM config " ;
serial_config_driver . bConfigurationValue = 2 ;
device_desc . bDeviceClass = USB_CLASS_COMM ;
device_desc . idProduct =
2009-02-11 14:11:36 -08:00
cpu_to_le16 ( GS_CDC_PRODUCT_ID ) ;
2008-08-18 17:39:30 -07:00
} else if ( use_obex ) {
serial_config_driver . label = " CDC OBEX config " ;
serial_config_driver . bConfigurationValue = 3 ;
device_desc . bDeviceClass = USB_CLASS_COMM ;
device_desc . idProduct =
2009-02-11 14:11:36 -08:00
cpu_to_le16 ( GS_CDC_OBEX_PRODUCT_ID ) ;
2005-04-16 15:20:36 -07:00
} else {
2008-06-19 18:19:03 -07:00
serial_config_driver . label = " Generic Serial config " ;
serial_config_driver . bConfigurationValue = 1 ;
device_desc . bDeviceClass = USB_CLASS_VENDOR_SPEC ;
device_desc . idProduct =
2009-02-11 14:11:36 -08:00
cpu_to_le16 ( GS_PRODUCT_ID ) ;
2005-04-16 15:20:36 -07:00
}
2008-06-19 18:19:03 -07:00
strings_dev [ STRING_DESCRIPTION_IDX ] . s = serial_config_driver . label ;
2008-05-07 16:00:36 -07:00
2012-09-06 20:11:04 +02:00
return usb_composite_probe ( & gserial_driver ) ;
2008-05-07 16:00:36 -07:00
}
2008-06-19 18:19:03 -07:00
module_init ( init ) ;
2008-05-07 16:00:36 -07:00
2008-06-19 18:19:03 -07:00
static void __exit cleanup ( void )
2008-05-07 16:00:36 -07:00
{
2008-06-19 18:19:03 -07:00
usb_composite_unregister ( & gserial_driver ) ;
2008-05-07 16:00:36 -07:00
}
2008-06-19 18:19:03 -07:00
module_exit ( cleanup ) ;