2017-11-03 11:28:30 +01:00
// SPDX-License-Identifier: GPL-2.0+
2008-06-19 18:20:26 -07:00
/*
* cdc2 . c - - CDC Composite driver , with ECM and ACM support
*
* Copyright ( C ) 2008 David Brownell
* Copyright ( C ) 2008 Nokia Corporation
*/
# include <linux/kernel.h>
2011-07-03 16:09:31 -04:00
# include <linux/module.h>
2008-06-19 18:20:26 -07:00
# include "u_ether.h"
# include "u_serial.h"
2013-05-23 10:32:04 +02:00
# include "u_ecm.h"
2008-06-19 18:20:26 -07:00
# define DRIVER_DESC "CDC Composite Gadget"
# define DRIVER_VERSION "King Kamehameha Day 2008"
/*-------------------------------------------------------------------------*/
/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
* Instead : allocate your own , using normal USB - IF procedures .
*/
/* Thanks to NetChip Technologies for donating this product ID.
* It ' s for devices with only this composite CDC configuration .
*/
# define CDC_VENDOR_NUM 0x0525 /* NetChip */
# define CDC_PRODUCT_NUM 0xa4aa /* CDC Composite: ECM + ACM */
2012-09-10 15:01:53 +02:00
USB_GADGET_COMPOSITE_OPTIONS ( ) ;
2008-06-19 18:20:26 -07: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 ( ) ;
2008-08-18 17:43:56 -07:00
/*-------------------------------------------------------------------------*/
2008-06-19 18:20:26 -07:00
static struct usb_device_descriptor device_desc = {
. bLength = sizeof device_desc ,
. bDescriptorType = USB_DT_DEVICE ,
2015-10-20 18:33:13 +02:00
/* .bcdUSB = DYNAMIC */
2008-06-19 18:20:26 -07:00
. bDeviceClass = USB_CLASS_COMM ,
. bDeviceSubClass = 0 ,
. bDeviceProtocol = 0 ,
/* .bMaxPacketSize0 = f(hardware) */
/* Vendor and product id can be overridden by module parameters. */
2009-02-11 14:11:36 -08:00
. idVendor = cpu_to_le16 ( CDC_VENDOR_NUM ) ,
. idProduct = cpu_to_le16 ( CDC_PRODUCT_NUM ) ,
2008-06-19 18:20:26 -07:00
/* .bcdDevice = f(hardware) */
/* .iManufacturer = DYNAMIC */
/* .iProduct = DYNAMIC */
/* NO SERIAL NUMBER */
. bNumConfigurations = 1 ,
} ;
2015-07-09 15:18:52 +08:00
static const struct usb_descriptor_header * otg_desc [ 2 ] ;
2008-06-19 18:20:26 -07:00
/* string IDs are assigned dynamically */
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 = DRIVER_DESC ,
[ USB_GADGET_SERIAL_IDX ] . s = " " ,
2008-06-19 18:20:26 -07:00
{ } /* 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 ,
} ;
/*-------------------------------------------------------------------------*/
2012-12-23 21:10:09 +01:00
static struct usb_function * f_acm ;
static struct usb_function_instance * fi_serial ;
2008-06-19 18:20:26 -07:00
2013-05-23 10:32:04 +02:00
static struct usb_function * f_ecm ;
static struct usb_function_instance * fi_ecm ;
2008-06-19 18:20:26 -07:00
/*
* We _always_ have both CDC ECM and CDC ACM functions .
*/
2015-04-11 00:14:21 +02:00
static int cdc_do_config ( struct usb_configuration * c )
2008-06-19 18:20:26 -07:00
{
int status ;
if ( gadget_is_otg ( c - > cdev - > gadget ) ) {
c - > descriptors = otg_desc ;
c - > bmAttributes | = USB_CONFIG_ATT_WAKEUP ;
}
2013-05-23 10:32:04 +02:00
f_ecm = usb_get_function ( fi_ecm ) ;
if ( IS_ERR ( f_ecm ) ) {
status = PTR_ERR ( f_ecm ) ;
goto err_get_ecm ;
}
status = usb_add_function ( c , f_ecm ) ;
if ( status )
goto err_add_ecm ;
2008-06-19 18:20:26 -07:00
2012-12-23 21:10:09 +01:00
f_acm = usb_get_function ( fi_serial ) ;
2013-04-06 17:25:21 +08:00
if ( IS_ERR ( f_acm ) ) {
status = PTR_ERR ( f_acm ) ;
2013-08-01 16:07:48 +02:00
goto err_get_acm ;
2013-04-06 17:25:21 +08:00
}
2012-12-23 21:10:09 +01:00
status = usb_add_function ( c , f_acm ) ;
if ( status )
2013-05-23 10:32:04 +02:00
goto err_add_acm ;
2008-06-19 18:20:26 -07:00
return 0 ;
2013-05-23 10:32:04 +02:00
err_add_acm :
2012-12-23 21:10:09 +01:00
usb_put_function ( f_acm ) ;
2013-05-23 10:32:04 +02:00
err_get_acm :
usb_remove_function ( c , f_ecm ) ;
err_add_ecm :
usb_put_function ( f_ecm ) ;
err_get_ecm :
2012-12-23 21:10:09 +01:00
return status ;
2008-06-19 18:20:26 -07:00
}
static struct usb_configuration cdc_config_driver = {
. label = " CDC Composite (ECM + ACM) " ,
. bConfigurationValue = 1 ,
/* .iConfiguration = DYNAMIC */
. bmAttributes = USB_CONFIG_ATT_SELFPOWER ,
} ;
/*-------------------------------------------------------------------------*/
2015-04-11 00:14:21 +02:00
static int cdc_bind ( struct usb_composite_dev * cdev )
2008-06-19 18:20:26 -07:00
{
struct usb_gadget * gadget = cdev - > gadget ;
2013-05-23 10:32:04 +02:00
struct f_ecm_opts * ecm_opts ;
2008-06-19 18:20:26 -07:00
int status ;
if ( ! can_support_ecm ( cdev - > gadget ) ) {
2008-08-18 17:43:56 -07:00
dev_err ( & gadget - > dev , " controller '%s' not usable \n " ,
gadget - > name ) ;
2008-06-19 18:20:26 -07:00
return - EINVAL ;
}
2013-05-23 10:32:04 +02:00
fi_ecm = usb_get_function_instance ( " ecm " ) ;
if ( IS_ERR ( fi_ecm ) )
return PTR_ERR ( fi_ecm ) ;
ecm_opts = container_of ( fi_ecm , struct f_ecm_opts , func_inst ) ;
gether_set_qmult ( ecm_opts - > net , qmult ) ;
if ( ! gether_set_host_addr ( ecm_opts - > net , host_addr ) )
pr_info ( " using host ethernet address: %s " , host_addr ) ;
if ( ! gether_set_dev_addr ( ecm_opts - > net , dev_addr ) )
pr_info ( " using self ethernet address: %s " , dev_addr ) ;
fi_serial = usb_get_function_instance ( " acm " ) ;
if ( IS_ERR ( fi_serial ) ) {
status = PTR_ERR ( fi_serial ) ;
goto fail ;
}
2008-06-19 18:20:26 -07:00
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue .
*/
2012-09-06 20:11:16 +02:00
status = usb_string_ids_tab ( cdev , strings_dev ) ;
2008-06-19 18:20:26 -07:00
if ( status < 0 )
goto fail1 ;
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 ;
2008-06-19 18:20:26 -07:00
2015-07-09 15:18:52 +08:00
if ( gadget_is_otg ( gadget ) & & ! otg_desc [ 0 ] ) {
struct usb_descriptor_header * usb_desc ;
usb_desc = usb_otg_descriptor_alloc ( gadget ) ;
if ( ! usb_desc )
goto fail1 ;
usb_otg_descriptor_init ( gadget , usb_desc ) ;
otg_desc [ 0 ] = usb_desc ;
otg_desc [ 1 ] = NULL ;
}
2008-06-19 18:20:26 -07:00
/* register our configuration */
2010-08-12 17:43:55 +02:00
status = usb_add_config ( cdev , & cdc_config_driver , cdc_do_config ) ;
2008-06-19 18:20:26 -07:00
if ( status < 0 )
2015-07-09 15:18:52 +08:00
goto fail2 ;
2008-06-19 18:20:26 -07:00
2012-09-10 15:01:53 +02:00
usb_composite_overwrite_options ( cdev , & coverwrite ) ;
2008-08-18 17:43:56 -07:00
dev_info ( & gadget - > dev , " %s, version: " DRIVER_VERSION " \n " ,
DRIVER_DESC ) ;
2008-06-19 18:20:26 -07:00
return 0 ;
2015-07-09 15:18:52 +08:00
fail2 :
kfree ( otg_desc [ 0 ] ) ;
otg_desc [ 0 ] = NULL ;
2008-06-19 18:20:26 -07:00
fail1 :
2013-05-23 10:32:04 +02:00
usb_put_function_instance ( fi_serial ) ;
fail :
usb_put_function_instance ( fi_ecm ) ;
2008-06-19 18:20:26 -07:00
return status ;
}
2015-04-11 00:14:21 +02:00
static int cdc_unbind ( struct usb_composite_dev * cdev )
2008-06-19 18:20:26 -07:00
{
2012-12-23 21:10:09 +01:00
usb_put_function ( f_acm ) ;
usb_put_function_instance ( fi_serial ) ;
2013-05-23 10:32:04 +02:00
if ( ! IS_ERR_OR_NULL ( f_ecm ) )
usb_put_function ( f_ecm ) ;
if ( ! IS_ERR_OR_NULL ( fi_ecm ) )
usb_put_function_instance ( fi_ecm ) ;
2015-07-09 15:18:52 +08:00
kfree ( otg_desc [ 0 ] ) ;
otg_desc [ 0 ] = NULL ;
2008-06-19 18:20:26 -07:00
return 0 ;
}
2015-04-11 00:14:21 +02:00
static struct usb_composite_driver cdc_driver = {
2008-06-19 18:20:26 -07:00
. name = " g_cdc " ,
. 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 = cdc_bind ,
2015-04-11 00:14:21 +02:00
. unbind = cdc_unbind ,
2008-06-19 18:20:26 -07:00
} ;
2014-07-09 18:09:56 +02:00
module_usb_composite_driver ( cdc_driver ) ;
2008-06-19 18:20:26 -07:00
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_AUTHOR ( " David Brownell " ) ;
MODULE_LICENSE ( " GPL " ) ;