2005-04-17 02:20:36 +04:00
/*
* zero . c - - Gadget Zero , for USB development
*
2008-06-20 05:18:27 +04:00
* Copyright ( C ) 2003 - 2008 David Brownell
* Copyright ( C ) 2008 by Nokia Corporation
2005-04-17 02:20:36 +04:00
*
2007-08-02 23:20:05 +04:00
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
2005-04-17 02:20:36 +04:00
*
2007-08-02 23:20:05 +04:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2005-04-17 02:20:36 +04:00
*
2007-08-02 23:20:05 +04:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2005-04-17 02:20:36 +04:00
*/
/*
* Gadget Zero only needs two bulk endpoints , and is an example of how you
* can write a hardware - agnostic gadget driver running inside a USB device .
2008-04-19 05:47:54 +04:00
* Some hardware details are visible , but don ' t affect most of the driver .
2005-04-17 02:20:36 +04:00
*
* Use it with the Linux host / master side " usbtest " driver to get a basic
* functional test of your device - side usb stack , or with " usb-skeleton " .
*
* It supports two similar configurations . One sinks whatever the usb host
* writes , and in return sources zeroes . The other loops whatever the host
2008-06-20 05:18:27 +04:00
* writes back , so the host can read it .
2005-04-17 02:20:36 +04:00
*
* Many drivers will only have one configuration , letting them be much
* simpler if they also don ' t support high speed operation ( like this
* driver does ) .
2007-08-02 23:20:05 +04:00
*
* Why is * this * driver using two configurations , rather than setting up
* two interfaces with different functions ? To help verify that multiple
* configuration infrastucture is working correctly ; also , so that it can
* work with low capability USB controllers without four bulk endpoints .
2005-04-17 02:20:36 +04:00
*/
2008-06-20 05:18:27 +04:00
/*
* driver assumes self - powered hardware , and
* has no way for users to trigger remote wakeup .
*/
2007-08-02 23:20:05 +04:00
/* #define VERBOSE_DEBUG */
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/utsname.h>
# include <linux/device.h>
2008-06-20 05:18:27 +04:00
# include "g_zero.h"
2005-04-17 02:20:36 +04:00
# include "gadget_chips.h"
2008-08-19 04:41:31 +04:00
/*-------------------------------------------------------------------------*/
/*
* 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 "f_sourcesink.c"
# include "f_loopback.c"
2005-04-17 02:20:36 +04:00
/*-------------------------------------------------------------------------*/
2008-06-20 05:18:27 +04:00
# define DRIVER_VERSION "Cinco de Mayo 2008"
2005-04-17 02:20:36 +04:00
2008-04-19 05:47:54 +04:00
static const char longname [ ] = " Gadget Zero " ;
2005-04-17 02:20:36 +04:00
2008-06-20 05:18:27 +04:00
unsigned buflen = 4096 ;
module_param ( buflen , uint , 0 ) ;
2005-04-17 02:20:36 +04:00
/*
* Normally the " loopback " configuration is second ( index 1 ) so
* it ' s not the default . Here ' s where to change that order , to
2008-06-20 05:18:27 +04:00
* work better with hosts where config changes are problematic or
* controllers ( like original superh ) that only support one config .
2005-04-17 02:20:36 +04:00
*/
static int loopdefault = 0 ;
2008-04-19 05:47:54 +04:00
module_param ( loopdefault , bool , S_IRUGO | S_IWUSR ) ;
2005-04-17 02:20:36 +04:00
/*-------------------------------------------------------------------------*/
/* Thanks to NetChip Technologies for donating this product ID.
*
* DO NOT REUSE THESE IDs with a protocol - incompatible driver ! ! Ever ! !
* Instead : allocate your own , using normal USB - IF procedures .
*/
# ifndef CONFIG_USB_ZERO_HNPTEST
# define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
# define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
# else
# define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
# define DRIVER_PRODUCT_NUM 0xbadd
# endif
/*-------------------------------------------------------------------------*/
2008-04-19 05:47:54 +04:00
static struct usb_device_descriptor device_desc = {
2005-04-17 02:20:36 +04:00
. bLength = sizeof device_desc ,
. bDescriptorType = USB_DT_DEVICE ,
2008-04-19 05:47:54 +04:00
. bcdUSB = __constant_cpu_to_le16 ( 0x0200 ) ,
2005-04-17 02:20:36 +04:00
. bDeviceClass = USB_CLASS_VENDOR_SPEC ,
2008-04-19 05:47:54 +04:00
. idVendor = __constant_cpu_to_le16 ( DRIVER_VENDOR_NUM ) ,
. idProduct = __constant_cpu_to_le16 ( DRIVER_PRODUCT_NUM ) ,
2005-04-17 02:20:36 +04:00
. bNumConfigurations = 2 ,
} ;
2008-06-20 05:18:27 +04:00
# ifdef CONFIG_USB_OTG
2008-04-19 05:47:54 +04:00
static struct usb_otg_descriptor otg_descriptor = {
2005-04-17 02:20:36 +04:00
. bLength = sizeof otg_descriptor ,
. bDescriptorType = USB_DT_OTG ,
2008-06-20 05:18:27 +04:00
/* REVISIT SRP-only hardware is possible, although
* it would not be called " OTG " . . .
*/
. bmAttributes = USB_OTG_SRP | USB_OTG_HNP ,
2005-04-17 02:20:36 +04:00
} ;
2008-06-20 05:18:27 +04:00
const struct usb_descriptor_header * otg_desc [ ] = {
2005-04-17 02:20:36 +04:00
( struct usb_descriptor_header * ) & otg_descriptor ,
NULL ,
} ;
2008-06-20 05:18:27 +04:00
# endif
2005-04-17 02:20:36 +04:00
2008-06-20 05:18:27 +04:00
/* string IDs are assigned dynamically */
2005-04-17 02:20:36 +04:00
2008-06-20 05:18:27 +04:00
# define STRING_MANUFACTURER_IDX 0
# define STRING_PRODUCT_IDX 1
# define STRING_SERIAL_IDX 2
2005-04-17 02:20:36 +04:00
2007-08-02 23:20:05 +04:00
static char manufacturer [ 50 ] ;
2005-04-17 02:20:36 +04:00
2007-08-02 23:20:05 +04:00
/* default serial number takes at least two packets */
static char serial [ ] = " 0123456789.0123456789.0123456789 " ;
2005-04-17 02:20:36 +04:00
2008-06-20 05:18:27 +04:00
static struct usb_string strings_dev [ ] = {
[ STRING_MANUFACTURER_IDX ] . s = manufacturer ,
[ STRING_PRODUCT_IDX ] . s = longname ,
[ STRING_SERIAL_IDX ] . s = serial ,
2005-04-17 02:20:36 +04:00
{ } /* end of list */
} ;
2008-06-20 05:18:27 +04:00
static struct usb_gadget_strings stringtab_dev = {
2005-04-17 02:20:36 +04:00
. language = 0x0409 , /* en-us */
2008-06-20 05:18:27 +04:00
. strings = strings_dev ,
2005-04-17 02:20:36 +04:00
} ;
2008-06-20 05:18:27 +04:00
static struct usb_gadget_strings * dev_strings [ ] = {
& stringtab_dev ,
NULL ,
} ;
2005-04-17 02:20:36 +04:00
/*-------------------------------------------------------------------------*/
2008-06-20 05:18:27 +04:00
struct usb_request * alloc_ep_req ( struct usb_ep * ep )
2005-04-17 02:20:36 +04:00
{
struct usb_request * req ;
2008-04-19 05:47:54 +04:00
req = usb_ep_alloc_request ( ep , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( req ) {
2008-06-20 05:18:27 +04:00
req - > length = buflen ;
req - > buf = kmalloc ( buflen , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! req - > buf ) {
2008-04-19 05:47:54 +04:00
usb_ep_free_request ( ep , req ) ;
2005-04-17 02:20:36 +04:00
req = NULL ;
}
}
return req ;
}
2008-06-20 05:18:27 +04:00
void free_ep_req ( struct usb_ep * ep , struct usb_request * req )
2005-04-17 02:20:36 +04:00
{
2007-07-01 22:04:54 +04:00
kfree ( req - > buf ) ;
2008-04-19 05:47:54 +04:00
usb_ep_free_request ( ep , req ) ;
2005-04-17 02:20:36 +04:00
}
2008-06-20 05:18:27 +04:00
static void disable_ep ( struct usb_composite_dev * cdev , struct usb_ep * ep )
2005-04-17 02:20:36 +04:00
{
2008-06-20 05:18:27 +04:00
int value ;
if ( ep - > driver_data ) {
value = usb_ep_disable ( ep ) ;
if ( value < 0 )
DBG ( cdev , " disable %s --> %d \n " ,
ep - > name , value ) ;
ep - > driver_data = NULL ;
2005-04-17 02:20:36 +04:00
}
}
2008-06-20 05:18:27 +04:00
void disable_endpoints ( struct usb_composite_dev * cdev ,
struct usb_ep * in , struct usb_ep * out )
2005-04-17 02:20:36 +04:00
{
2008-06-20 05:18:27 +04:00
disable_ep ( cdev , in ) ;
disable_ep ( cdev , out ) ;
2005-04-17 02:20:36 +04:00
}
/*-------------------------------------------------------------------------*/
2008-06-20 05:18:27 +04:00
static int __init zero_bind ( struct usb_composite_dev * cdev )
2005-04-17 02:20:36 +04:00
{
2005-07-14 02:18:30 +04:00
int gcnum ;
2008-06-20 05:18:27 +04:00
struct usb_gadget * gadget = cdev - > gadget ;
int id ;
2005-07-14 02:18:30 +04:00
2008-06-20 05:18:27 +04:00
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue .
2005-07-14 02:18:30 +04:00
*/
2008-06-20 05:18:27 +04:00
id = usb_string_id ( cdev ) ;
if ( id < 0 )
return id ;
strings_dev [ STRING_MANUFACTURER_IDX ] . id = id ;
device_desc . iManufacturer = id ;
id = usb_string_id ( cdev ) ;
if ( id < 0 )
return id ;
strings_dev [ STRING_PRODUCT_IDX ] . id = id ;
device_desc . iProduct = id ;
id = usb_string_id ( cdev ) ;
if ( id < 0 )
return id ;
strings_dev [ STRING_SERIAL_IDX ] . id = id ;
device_desc . iSerialNumber = id ;
/* Register primary, then secondary configuration. Note that
* SH3 only allows one config . . .
2005-04-17 02:20:36 +04:00
*/
2008-06-20 05:18:27 +04:00
if ( loopdefault ) {
loopback_add ( cdev ) ;
if ( ! gadget_is_sh ( gadget ) )
sourcesink_add ( cdev ) ;
} else {
sourcesink_add ( cdev ) ;
if ( ! gadget_is_sh ( gadget ) )
loopback_add ( cdev ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-19 05:47:54 +04:00
gcnum = usb_gadget_controller_number ( gadget ) ;
2005-07-14 02:18:30 +04:00
if ( gcnum > = 0 )
2008-04-19 05:47:54 +04:00
device_desc . bcdDevice = cpu_to_le16 ( 0x0200 + gcnum ) ;
2005-07-14 02:18:30 +04:00
else {
2005-04-17 02:20:36 +04:00
/* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk - capable hardware .
2008-06-20 05:18:27 +04:00
* so just warn about unrcognized controllers - - don ' t panic .
2005-04-17 02:20:36 +04:00
*
* things like configuration and altsetting numbering
* can need hardware - specific attention though .
*/
2007-11-19 23:58:36 +03:00
pr_warning ( " %s: controller '%s' not recognized \n " ,
2008-06-20 05:18:27 +04:00
longname , gadget - > name ) ;
2008-04-19 05:47:54 +04:00
device_desc . bcdDevice = __constant_cpu_to_le16 ( 0x9999 ) ;
2005-04-17 02:20:36 +04:00
}
2008-06-20 05:18:27 +04:00
INFO ( cdev , " %s, version: " DRIVER_VERSION " \n " , longname ) ;
2005-04-17 02:20:36 +04:00
2008-04-19 05:47:54 +04:00
snprintf ( manufacturer , sizeof manufacturer , " %s %s with %s " ,
2006-10-02 13:18:13 +04:00
init_utsname ( ) - > sysname , init_utsname ( ) - > release ,
2005-04-17 02:20:36 +04:00
gadget - > name ) ;
return 0 ;
}
2008-06-20 05:18:27 +04:00
static struct usb_composite_driver zero_driver = {
. name = " zero " ,
. dev = & device_desc ,
. strings = dev_strings ,
2005-04-17 02:20:36 +04:00
. bind = zero_bind ,
} ;
2007-08-02 23:20:05 +04:00
MODULE_AUTHOR ( " David Brownell " ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-04-17 02:20:36 +04:00
2008-04-19 05:47:54 +04:00
static int __init init ( void )
2005-04-17 02:20:36 +04:00
{
2008-06-20 05:18:27 +04:00
return usb_composite_register ( & zero_driver ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-19 05:47:54 +04:00
module_init ( init ) ;
2005-04-17 02:20:36 +04:00
2008-04-19 05:47:54 +04:00
static void __exit cleanup ( void )
2005-04-17 02:20:36 +04:00
{
2008-06-20 05:18:27 +04:00
usb_composite_unregister ( & zero_driver ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-19 05:47:54 +04:00
module_exit ( cleanup ) ;