2005-04-17 02:20:36 +04:00
/*
2006-10-04 01:01:26 +04:00
* drivers / usb / core / usb . c
2005-04-17 02:20:36 +04:00
*
* ( C ) Copyright Linus Torvalds 1999
* ( C ) Copyright Johannes Erdfelt 1999 - 2001
* ( C ) Copyright Andreas Gal 1999
* ( C ) Copyright Gregory P . Smith 1999
* ( C ) Copyright Deti Fliegl 1999 ( new USB architecture )
* ( C ) Copyright Randy Dunlap 2000
* ( C ) Copyright David Brownell 2000 - 2004
* ( C ) Copyright Yggdrasil Computing , Inc . 2000
* ( usb_device_id matching changes by Adam J . Richter )
* ( C ) Copyright Greg Kroah - Hartman 2002 - 2003
*
* NOTE ! This is not actually a driver at all , rather this is
* just a collection of helper routines that implement the
* generic USB things that the real drivers can use . .
*
* Think of this as a " USB library " rather than anything else .
* It should be considered a slave , with no callbacks . Callbacks
* are evil .
*/
# include <linux/module.h>
2007-02-20 23:00:53 +03:00
# include <linux/moduleparam.h>
2005-04-17 02:20:36 +04:00
# include <linux/string.h>
# include <linux/bitops.h>
# include <linux/slab.h>
# include <linux/interrupt.h> /* for in_interrupt() */
# include <linux/kmod.h>
# include <linux/init.h>
# include <linux/spinlock.h>
# include <linux/errno.h>
# include <linux/usb.h>
2006-01-11 17:55:29 +03:00
# include <linux/mutex.h>
2006-09-19 18:14:07 +04:00
# include <linux/workqueue.h>
2009-04-25 01:56:26 +04:00
# include <linux/debugfs.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
2007-10-30 12:35:04 +03:00
# include <linux/scatterlist.h>
2005-04-17 02:20:36 +04:00
# include <linux/mm.h>
# include <linux/dma-mapping.h>
# include "hcd.h"
# include "usb.h"
const char * usbcore_name = " usbcore " ;
static int nousb ; /* Disable USB when built into kernel image */
2007-03-13 23:37:30 +03:00
/* Workqueue for autosuspend and for remote wakeup of root hubs */
struct workqueue_struct * ksuspend_usb_wq ;
2006-09-19 18:14:07 +04:00
2007-02-20 23:00:53 +03:00
# ifdef CONFIG_USB_SUSPEND
static int usb_autosuspend_delay = 2 ; /* Default delay value,
* in seconds */
2007-03-13 23:39:15 +03:00
module_param_named ( autosuspend , usb_autosuspend_delay , int , 0644 ) ;
2007-02-20 23:00:53 +03:00
MODULE_PARM_DESC ( autosuspend , " default autosuspend delay " ) ;
# else
# define usb_autosuspend_delay 0
# endif
2005-04-17 02:20:36 +04:00
/**
* usb_ifnum_to_if - get the interface object with a given interface number
* @ dev : the device whose current configuration is considered
* @ ifnum : the desired interface
*
* This walks the device descriptor for the currently active configuration
* and returns a pointer to the interface with that particular interface
* number , or null .
*
* Note that configuration descriptors are not required to assign interface
* numbers sequentially , so that it would be incorrect to assume that
* the first interface in that descriptor corresponds to interface zero .
* This routine helps device drivers avoid such mistakes .
* However , you should make sure that you do the right thing with any
* alternate settings available for this interfaces .
*
* Don ' t call this function unless you are bound to one of the interfaces
* on this device or you have locked the device !
*/
2006-08-27 06:48:11 +04:00
struct usb_interface * usb_ifnum_to_if ( const struct usb_device * dev ,
unsigned ifnum )
2005-04-17 02:20:36 +04:00
{
struct usb_host_config * config = dev - > actconfig ;
int i ;
if ( ! config )
return NULL ;
for ( i = 0 ; i < config - > desc . bNumInterfaces ; i + + )
if ( config - > interface [ i ] - > altsetting [ 0 ]
. desc . bInterfaceNumber = = ifnum )
return config - > interface [ i ] ;
return NULL ;
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_ifnum_to_if ) ;
2005-04-17 02:20:36 +04:00
/**
2008-03-01 09:03:07 +03:00
* usb_altnum_to_altsetting - get the altsetting structure with a given alternate setting number .
2005-04-17 02:20:36 +04:00
* @ intf : the interface containing the altsetting in question
* @ altnum : the desired alternate setting number
*
* This searches the altsetting array of the specified interface for
* an entry with the correct bAlternateSetting value and returns a pointer
* to that entry , or null .
*
* Note that altsettings need not be stored sequentially by number , so
* it would be incorrect to assume that the first altsetting entry in
* the array corresponds to altsetting zero . This routine helps device
* drivers avoid such mistakes .
*
* Don ' t call this function unless you are bound to the intf interface
* or you have locked the device !
*/
2008-01-31 02:21:33 +03:00
struct usb_host_interface * usb_altnum_to_altsetting (
const struct usb_interface * intf ,
unsigned int altnum )
2005-04-17 02:20:36 +04:00
{
int i ;
for ( i = 0 ; i < intf - > num_altsetting ; i + + ) {
if ( intf - > altsetting [ i ] . desc . bAlternateSetting = = altnum )
return & intf - > altsetting [ i ] ;
}
return NULL ;
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_altnum_to_altsetting ) ;
2005-04-17 02:20:36 +04:00
2008-01-31 02:21:33 +03:00
static int __find_interface ( struct device * dev , void * data )
2005-03-21 22:09:40 +03:00
{
2009-11-18 21:02:13 +03:00
int * minor = data ;
2005-12-22 04:24:54 +03:00
struct usb_interface * intf ;
2005-03-21 22:09:40 +03:00
2009-05-04 21:48:32 +04:00
if ( ! is_usb_interface ( dev ) )
2005-03-21 22:09:40 +03:00
return 0 ;
intf = to_usb_interface ( dev ) ;
2009-11-18 21:02:13 +03:00
if ( intf - > minor ! = - 1 & & intf - > minor = = * minor )
2005-03-21 22:09:40 +03:00
return 1 ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
/**
* usb_find_interface - find usb_interface pointer for driver and device
* @ drv : the driver whose current configuration is considered
* @ minor : the minor number of the desired device
*
2009-11-18 21:02:13 +03:00
* This walks the bus device list and returns a pointer to the interface
2005-04-17 02:20:36 +04:00
* with the matching minor . Note , this only works for devices that share the
* USB major number .
*/
struct usb_interface * usb_find_interface ( struct usb_driver * drv , int minor )
{
2009-11-18 21:02:13 +03:00
struct device * dev ;
dev = bus_find_device ( & usb_bus_type , NULL , & minor , __find_interface ) ;
/* Drop reference count from bus_find_device */
put_device ( dev ) ;
return dev ? to_usb_interface ( dev ) : NULL ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_find_interface ) ;
2005-04-17 02:20:36 +04:00
/**
* usb_release_dev - free a usb device structure when all users of it are finished .
* @ dev : device that ' s been disconnected
*
* Will be called only by the device core when all users of this usb device are
* done .
*/
static void usb_release_dev ( struct device * dev )
{
struct usb_device * udev ;
2009-04-28 06:57:26 +04:00
struct usb_hcd * hcd ;
2005-04-17 02:20:36 +04:00
udev = to_usb_device ( dev ) ;
2009-04-28 06:57:26 +04:00
hcd = bus_to_hcd ( udev - > bus ) ;
2005-04-17 02:20:36 +04:00
usb_destroy_configuration ( udev ) ;
2009-04-28 06:57:26 +04:00
/* Root hubs aren't real devices, so don't free HCD resources */
if ( hcd - > driver - > free_dev & & udev - > parent )
hcd - > driver - > free_dev ( hcd , udev ) ;
usb_put_hcd ( hcd ) ;
2005-04-17 02:20:36 +04:00
kfree ( udev - > product ) ;
kfree ( udev - > manufacturer ) ;
kfree ( udev - > serial ) ;
kfree ( udev ) ;
}
2007-11-06 23:01:52 +03:00
# ifdef CONFIG_HOTPLUG
static int usb_dev_uevent ( struct device * dev , struct kobj_uevent_env * env )
{
struct usb_device * usb_dev ;
usb_dev = to_usb_device ( dev ) ;
if ( add_uevent_var ( env , " BUSNUM=%03d " , usb_dev - > bus - > busnum ) )
return - ENOMEM ;
if ( add_uevent_var ( env , " DEVNUM=%03d " , usb_dev - > devnum ) )
return - ENOMEM ;
return 0 ;
}
# else
static int usb_dev_uevent ( struct device * dev , struct kobj_uevent_env * env )
{
return - ENODEV ;
}
# endif /* CONFIG_HOTPLUG */
2006-08-30 23:47:02 +04:00
# ifdef CONFIG_PM
2006-09-19 18:14:07 +04:00
static int ksuspend_usb_init ( void )
{
2007-05-22 17:38:39 +04:00
/* This workqueue is supposed to be both freezable and
* singlethreaded . Its job doesn ' t justify running on more
* than one CPU .
*/
2008-02-25 02:35:04 +03:00
ksuspend_usb_wq = create_freezeable_workqueue ( " ksuspend_usbd " ) ;
2006-09-19 18:14:07 +04:00
if ( ! ksuspend_usb_wq )
return - ENOMEM ;
return 0 ;
}
static void ksuspend_usb_cleanup ( void )
{
destroy_workqueue ( ksuspend_usb_wq ) ;
}
2008-08-12 22:34:10 +04:00
/* USB device Power-Management thunks.
* There ' s no need to distinguish here between quiescing a USB device
* and powering it down ; the generic_suspend ( ) routine takes care of
* it by skipping the usb_port_suspend ( ) call for a quiesce . And for
* USB interfaces there ' s no difference at all .
*/
static int usb_dev_prepare ( struct device * dev )
{
return 0 ; /* Implement eventually? */
}
static void usb_dev_complete ( struct device * dev )
{
/* Currently used only for rebinding interfaces */
2008-11-26 00:39:18 +03:00
usb_resume ( dev , PMSG_RESUME ) ; /* Message event is meaningless */
2008-08-12 22:34:10 +04:00
}
static int usb_dev_suspend ( struct device * dev )
{
return usb_suspend ( dev , PMSG_SUSPEND ) ;
}
static int usb_dev_resume ( struct device * dev )
{
2008-11-26 00:39:18 +03:00
return usb_resume ( dev , PMSG_RESUME ) ;
2008-08-12 22:34:10 +04:00
}
static int usb_dev_freeze ( struct device * dev )
{
return usb_suspend ( dev , PMSG_FREEZE ) ;
}
static int usb_dev_thaw ( struct device * dev )
{
2008-11-26 00:39:18 +03:00
return usb_resume ( dev , PMSG_THAW ) ;
2008-08-12 22:34:10 +04:00
}
static int usb_dev_poweroff ( struct device * dev )
{
return usb_suspend ( dev , PMSG_HIBERNATE ) ;
}
static int usb_dev_restore ( struct device * dev )
{
2008-11-26 00:39:18 +03:00
return usb_resume ( dev , PMSG_RESTORE ) ;
2008-08-12 22:34:10 +04:00
}
2008-10-07 00:46:05 +04:00
static struct dev_pm_ops usb_device_pm_ops = {
2008-08-12 22:34:10 +04:00
. prepare = usb_dev_prepare ,
. complete = usb_dev_complete ,
. suspend = usb_dev_suspend ,
. resume = usb_dev_resume ,
. freeze = usb_dev_freeze ,
. thaw = usb_dev_thaw ,
. poweroff = usb_dev_poweroff ,
. restore = usb_dev_restore ,
} ;
2006-11-13 23:02:04 +03:00
# else
# define ksuspend_usb_init() 0
# define ksuspend_usb_cleanup() do {} while (0)
2008-10-07 00:46:05 +04:00
# define usb_device_pm_ops (*(struct dev_pm_ops *)0)
2006-11-13 23:02:04 +03:00
# endif /* CONFIG_PM */
2006-08-30 23:47:02 +04:00
2009-04-30 17:23:42 +04:00
2009-09-19 01:01:12 +04:00
static char * usb_devnode ( struct device * dev , mode_t * mode )
2009-04-30 17:23:42 +04:00
{
struct usb_device * usb_dev ;
usb_dev = to_usb_device ( dev ) ;
return kasprintf ( GFP_KERNEL , " bus/usb/%03d/%03d " ,
usb_dev - > bus - > busnum , usb_dev - > devnum ) ;
}
2008-08-12 22:34:10 +04:00
struct device_type usb_device_type = {
. name = " usb_device " ,
. release = usb_release_dev ,
. uevent = usb_dev_uevent ,
2009-09-19 01:01:12 +04:00
. devnode = usb_devnode ,
2008-08-12 22:34:10 +04:00
. pm = & usb_device_pm_ops ,
} ;
2007-08-01 07:34:00 +04:00
/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
static unsigned usb_bus_is_wusb ( struct usb_bus * bus )
{
struct usb_hcd * hcd = container_of ( bus , struct usb_hcd , self ) ;
return hcd - > wireless ;
}
2005-04-17 02:20:36 +04:00
/**
* usb_alloc_dev - usb device constructor ( usbcore - internal )
* @ parent : hub to which device is connected ; null to allocate a root hub
* @ bus : bus used to access the device
* @ port1 : one - based index of port ; ignored for root hubs
2007-01-23 23:55:28 +03:00
* Context : ! in_interrupt ( )
2005-04-17 02:20:36 +04:00
*
* Only hub drivers ( including virtual root hub drivers for host
* controllers ) should ever call this .
*
* This call may not be used in a non - sleeping context .
*/
2008-01-31 02:21:33 +03:00
struct usb_device * usb_alloc_dev ( struct usb_device * parent ,
struct usb_bus * bus , unsigned port1 )
2005-04-17 02:20:36 +04:00
{
struct usb_device * dev ;
2007-08-01 07:34:00 +04:00
struct usb_hcd * usb_hcd = container_of ( bus , struct usb_hcd , self ) ;
unsigned root_hub = 0 ;
2005-04-17 02:20:36 +04:00
2005-10-24 23:38:24 +04:00
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
return NULL ;
2006-08-30 19:32:52 +04:00
if ( ! usb_get_hcd ( bus_to_hcd ( bus ) ) ) {
2005-04-17 02:20:36 +04:00
kfree ( dev ) ;
return NULL ;
}
2009-04-28 06:57:26 +04:00
/* Root hubs aren't true devices, so don't allocate HCD resources */
if ( usb_hcd - > driver - > alloc_dev & & parent & &
! usb_hcd - > driver - > alloc_dev ( usb_hcd , dev ) ) {
usb_put_hcd ( bus_to_hcd ( bus ) ) ;
kfree ( dev ) ;
return NULL ;
}
2005-04-17 02:20:36 +04:00
device_initialize ( & dev - > dev ) ;
dev - > dev . bus = & usb_bus_type ;
2007-03-13 17:59:31 +03:00
dev - > dev . type = & usb_device_type ;
2008-04-30 23:37:19 +04:00
dev - > dev . groups = usb_device_groups ;
2005-04-17 02:20:36 +04:00
dev - > dev . dma_mask = bus - > controller - > dma_mask ;
2007-07-09 23:03:09 +04:00
set_dev_node ( & dev - > dev , dev_to_node ( bus - > controller ) ) ;
2005-04-17 02:20:36 +04:00
dev - > state = USB_STATE_ATTACHED ;
2007-10-04 01:56:03 +04:00
atomic_set ( & dev - > urbnum , 0 ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & dev - > ep0 . urb_list ) ;
dev - > ep0 . desc . bLength = USB_DT_ENDPOINT_SIZE ;
dev - > ep0 . desc . bDescriptorType = USB_DT_ENDPOINT ;
/* ep0 maxpacket comes later, from device descriptor */
2009-04-08 21:36:28 +04:00
usb_enable_endpoint ( dev , & dev - > ep0 , false ) ;
2007-09-10 19:34:26 +04:00
dev - > can_submit = 1 ;
2005-04-17 02:20:36 +04:00
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics , tools , driver model , etc . The
* string is a path along hub ports , from the root . Each device ' s
* dev - > devpath will be stable until USB is re - cabled , and hubs
2008-05-02 08:02:41 +04:00
* are often labeled with these port numbers . The name isn ' t
2005-04-17 02:20:36 +04:00
* as stable : bus - > busnum changes easily from modprobe order ,
* cardbus or pci hotplugging , and so on .
*/
2007-01-23 23:55:28 +03:00
if ( unlikely ( ! parent ) ) {
dev - > devpath [ 0 ] = ' 0 ' ;
2009-04-28 06:54:49 +04:00
dev - > route = 0 ;
2005-04-17 02:20:36 +04:00
dev - > dev . parent = bus - > controller ;
2008-05-02 08:02:41 +04:00
dev_set_name ( & dev - > dev , " usb%d " , bus - > busnum ) ;
2007-08-01 07:34:00 +04:00
root_hub = 1 ;
2005-04-17 02:20:36 +04:00
} else {
/* match any labeling on the hubs; it's one-based */
2009-04-28 06:54:49 +04:00
if ( parent - > devpath [ 0 ] = = ' 0 ' ) {
2007-01-23 23:55:28 +03:00
snprintf ( dev - > devpath , sizeof dev - > devpath ,
2005-04-17 02:20:36 +04:00
" %d " , port1 ) ;
2009-04-28 06:54:49 +04:00
/* Root ports are not counted in route string */
dev - > route = 0 ;
} else {
2007-01-23 23:55:28 +03:00
snprintf ( dev - > devpath , sizeof dev - > devpath ,
2005-04-17 02:20:36 +04:00
" %s.%d " , parent - > devpath , port1 ) ;
2009-09-04 21:53:17 +04:00
/* Route string assumes hubs have less than 16 ports */
if ( port1 < 15 )
dev - > route = parent - > route +
( port1 < < ( ( parent - > level - 1 ) * 4 ) ) ;
else
dev - > route = parent - > route +
( 15 < < ( ( parent - > level - 1 ) * 4 ) ) ;
2009-04-28 06:54:49 +04:00
}
2005-04-17 02:20:36 +04:00
dev - > dev . parent = & parent - > dev ;
2008-05-02 08:02:41 +04:00
dev_set_name ( & dev - > dev , " %d-%s " , bus - > busnum , dev - > devpath ) ;
2005-04-17 02:20:36 +04:00
/* hub driver sets up TT records */
}
2005-11-23 20:09:52 +03:00
dev - > portnum = port1 ;
2005-04-17 02:20:36 +04:00
dev - > bus = bus ;
dev - > parent = parent ;
INIT_LIST_HEAD ( & dev - > filelist ) ;
2006-08-30 23:47:02 +04:00
# ifdef CONFIG_PM
mutex_init ( & dev - > pm_mutex ) ;
2006-11-22 17:57:56 +03:00
INIT_DELAYED_WORK ( & dev - > autosuspend , usb_autosuspend_work ) ;
2008-11-13 00:19:49 +03:00
INIT_WORK ( & dev - > autoresume , usb_autoresume_work ) ;
2007-02-20 23:00:53 +03:00
dev - > autosuspend_delay = usb_autosuspend_delay * HZ ;
2007-12-22 03:54:15 +03:00
dev - > connect_time = jiffies ;
dev - > active_duration = - jiffies ;
2006-08-30 23:47:02 +04:00
# endif
2007-08-01 07:34:00 +04:00
if ( root_hub ) /* Root hub always ok [and always wired] */
dev - > authorized = 1 ;
else {
dev - > authorized = usb_hcd - > authorized_default ;
dev - > wusb = usb_bus_is_wusb ( bus ) ? 1 : 0 ;
}
2005-04-17 02:20:36 +04:00
return dev ;
}
/**
* usb_get_dev - increments the reference count of the usb device structure
* @ dev : the device being referenced
*
* Each live reference to a device should be refcounted .
*
* Drivers for USB interfaces should normally record such references in
* their probe ( ) methods , when they bind to an interface , and release
* them by calling usb_put_dev ( ) , in their disconnect ( ) methods .
*
* A pointer to the device with the incremented reference counter is returned .
*/
struct usb_device * usb_get_dev ( struct usb_device * dev )
{
if ( dev )
get_device ( & dev - > dev ) ;
return dev ;
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_get_dev ) ;
2005-04-17 02:20:36 +04:00
/**
* usb_put_dev - release a use of the usb device structure
* @ dev : device that ' s been disconnected
*
* Must be called when a user of a device is finished with it . When the last
* user of the device calls this function , the memory of the device is freed .
*/
void usb_put_dev ( struct usb_device * dev )
{
if ( dev )
put_device ( & dev - > dev ) ;
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_put_dev ) ;
2005-04-17 02:20:36 +04:00
/**
* usb_get_intf - increments the reference count of the usb interface structure
* @ intf : the interface being referenced
*
* Each live reference to a interface must be refcounted .
*
* Drivers for USB interfaces should normally record such references in
* their probe ( ) methods , when they bind to an interface , and release
* them by calling usb_put_intf ( ) , in their disconnect ( ) methods .
*
* A pointer to the interface with the incremented reference counter is
* returned .
*/
struct usb_interface * usb_get_intf ( struct usb_interface * intf )
{
if ( intf )
get_device ( & intf - > dev ) ;
return intf ;
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_get_intf ) ;
2005-04-17 02:20:36 +04:00
/**
* usb_put_intf - release a use of the usb interface structure
* @ intf : interface that ' s been decremented
*
* Must be called when a user of an interface is finished with it . When the
* last user of the interface calls this function , the memory of the interface
* is freed .
*/
void usb_put_intf ( struct usb_interface * intf )
{
if ( intf )
put_device ( & intf - > dev ) ;
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_put_intf ) ;
2005-04-17 02:20:36 +04:00
/* USB device locking
*
2005-11-18 01:10:32 +03:00
* USB devices and interfaces are locked using the semaphore in their
* embedded struct device . The hub driver guarantees that whenever a
* device is connected or disconnected , drivers are called with the
* USB device locked as well as their particular interface .
2005-04-17 02:20:36 +04:00
*
* Complications arise when several devices are to be locked at the same
* time . Only hub - aware drivers that are part of usbcore ever have to
2005-11-18 01:10:32 +03:00
* do this ; nobody else needs to worry about it . The rule for locking
* is simple :
2005-04-17 02:20:36 +04:00
*
* When locking both a device and its parent , always lock the
* the parent first .
*/
/**
2008-03-01 09:03:07 +03:00
* usb_lock_device_for_reset - cautiously acquire the lock for a usb device structure
2005-04-17 02:20:36 +04:00
* @ udev : device that ' s being locked
* @ iface : interface bound to the driver making the request ( optional )
*
* Attempts to acquire the device lock , but fails if the device is
* NOTATTACHED or SUSPENDED , or if iface is specified and the interface
* is neither BINDING nor BOUND . Rather than sleeping to wait for the
* lock , the routine polls repeatedly . This is to prevent deadlock with
* disconnect ; in some drivers ( such as usb - storage ) the disconnect ( )
2005-08-11 18:15:39 +04:00
* or suspend ( ) method will block waiting for a device reset to complete .
2005-04-17 02:20:36 +04:00
*
2008-11-04 19:29:27 +03:00
* Returns a negative error code for failure , otherwise 0.
2005-04-17 02:20:36 +04:00
*/
int usb_lock_device_for_reset ( struct usb_device * udev ,
2006-08-27 06:48:11 +04:00
const struct usb_interface * iface )
2005-04-17 02:20:36 +04:00
{
2005-08-11 18:15:39 +04:00
unsigned long jiffies_expire = jiffies + HZ ;
2005-04-17 02:20:36 +04:00
if ( udev - > state = = USB_STATE_NOTATTACHED )
return - ENODEV ;
if ( udev - > state = = USB_STATE_SUSPENDED )
return - EHOSTUNREACH ;
2008-11-04 19:29:27 +03:00
if ( iface & & ( iface - > condition = = USB_INTERFACE_UNBINDING | |
iface - > condition = = USB_INTERFACE_UNBOUND ) )
return - EINTR ;
2005-04-17 02:20:36 +04:00
2005-11-18 01:10:32 +03:00
while ( usb_trylock_device ( udev ) ! = 0 ) {
2005-08-11 18:15:39 +04:00
/* If we can't acquire the lock after waiting one second,
* we ' re probably deadlocked */
if ( time_after ( jiffies , jiffies_expire ) )
return - EBUSY ;
2005-04-17 02:20:36 +04:00
msleep ( 15 ) ;
if ( udev - > state = = USB_STATE_NOTATTACHED )
return - ENODEV ;
if ( udev - > state = = USB_STATE_SUSPENDED )
return - EHOSTUNREACH ;
2008-11-04 19:29:27 +03:00
if ( iface & & ( iface - > condition = = USB_INTERFACE_UNBINDING | |
iface - > condition = = USB_INTERFACE_UNBOUND ) )
2005-04-17 02:20:36 +04:00
return - EINTR ;
}
2008-11-04 19:29:27 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_lock_device_for_reset ) ;
2005-04-17 02:20:36 +04:00
static struct usb_device * match_device ( struct usb_device * dev ,
u16 vendor_id , u16 product_id )
{
struct usb_device * ret_dev = NULL ;
int child ;
dev_dbg ( & dev - > dev , " check for vendor %04x, product %04x ... \n " ,
le16_to_cpu ( dev - > descriptor . idVendor ) ,
le16_to_cpu ( dev - > descriptor . idProduct ) ) ;
/* see if this device matches */
if ( ( vendor_id = = le16_to_cpu ( dev - > descriptor . idVendor ) ) & &
( product_id = = le16_to_cpu ( dev - > descriptor . idProduct ) ) ) {
2007-01-23 23:55:28 +03:00
dev_dbg ( & dev - > dev , " matched this device! \n " ) ;
2005-04-17 02:20:36 +04:00
ret_dev = usb_get_dev ( dev ) ;
goto exit ;
}
/* look through all of the children of this device */
for ( child = 0 ; child < dev - > maxchild ; + + child ) {
if ( dev - > children [ child ] ) {
2005-11-18 01:10:32 +03:00
usb_lock_device ( dev - > children [ child ] ) ;
2005-04-17 02:20:36 +04:00
ret_dev = match_device ( dev - > children [ child ] ,
vendor_id , product_id ) ;
2005-11-18 01:10:32 +03:00
usb_unlock_device ( dev - > children [ child ] ) ;
2005-04-17 02:20:36 +04:00
if ( ret_dev )
goto exit ;
}
}
exit :
return ret_dev ;
}
/**
* usb_find_device - find a specific usb device in the system
* @ vendor_id : the vendor id of the device to find
* @ product_id : the product id of the device to find
*
* Returns a pointer to a struct usb_device if such a specified usb
* device is present in the system currently . The usage count of the
* device will be incremented if a device is found . Make sure to call
* usb_put_dev ( ) when the caller is finished with the device .
*
* If a device with the specified vendor and product id is not found ,
* NULL is returned .
*/
struct usb_device * usb_find_device ( u16 vendor_id , u16 product_id )
{
struct list_head * buslist ;
struct usb_bus * bus ;
struct usb_device * dev = NULL ;
2008-01-31 02:21:33 +03:00
2006-01-11 17:55:29 +03:00
mutex_lock ( & usb_bus_list_lock ) ;
2005-04-17 02:20:36 +04:00
for ( buslist = usb_bus_list . next ;
2008-01-31 02:21:33 +03:00
buslist ! = & usb_bus_list ;
2005-04-17 02:20:36 +04:00
buslist = buslist - > next ) {
bus = container_of ( buslist , struct usb_bus , bus_list ) ;
if ( ! bus - > root_hub )
continue ;
usb_lock_device ( bus - > root_hub ) ;
dev = match_device ( bus - > root_hub , vendor_id , product_id ) ;
usb_unlock_device ( bus - > root_hub ) ;
if ( dev )
goto exit ;
}
exit :
2006-01-11 17:55:29 +03:00
mutex_unlock ( & usb_bus_list_lock ) ;
2005-04-17 02:20:36 +04:00
return dev ;
}
/**
* usb_get_current_frame_number - return current bus frame number
* @ dev : the device whose bus is being queried
*
* Returns the current frame number for the USB host controller
* used with the given USB device . This can be used when scheduling
* isochronous requests .
*
* Note that different kinds of host controller have different
* " scheduling horizons " . While one type might support scheduling only
* 32 frames into the future , others could support scheduling up to
* 1024 frames into the future .
*/
int usb_get_current_frame_number ( struct usb_device * dev )
{
2007-01-23 23:55:28 +03:00
return usb_hcd_get_frame_number ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_get_current_frame_number ) ;
2005-04-17 02:20:36 +04:00
/*-------------------------------------------------------------------*/
/*
* __usb_get_extra_descriptor ( ) finds a descriptor of specific type in the
* extra field of the interface and endpoint descriptor structs .
*/
int __usb_get_extra_descriptor ( char * buffer , unsigned size ,
2008-01-31 02:21:33 +03:00
unsigned char type , void * * ptr )
2005-04-17 02:20:36 +04:00
{
struct usb_descriptor_header * header ;
while ( size > = sizeof ( struct usb_descriptor_header ) ) {
header = ( struct usb_descriptor_header * ) buffer ;
if ( header - > bLength < 2 ) {
printk ( KERN_ERR
" %s: bogus descriptor, type %d length %d \n " ,
usbcore_name ,
2008-01-31 02:21:33 +03:00
header - > bDescriptorType ,
2005-04-17 02:20:36 +04:00
header - > bLength ) ;
return - 1 ;
}
if ( header - > bDescriptorType = = type ) {
* ptr = header ;
return 0 ;
}
buffer + = header - > bLength ;
size - = header - > bLength ;
}
return - 1 ;
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( __usb_get_extra_descriptor ) ;
2005-04-17 02:20:36 +04:00
/**
* usb_buffer_alloc - allocate dma - consistent buffer for URB_NO_xxx_DMA_MAP
* @ dev : device the buffer will be used with
* @ size : requested buffer size
* @ mem_flags : affect whether allocation may block
* @ dma : used to return DMA address of buffer
*
* Return value is either null ( indicating no buffer could be allocated ) , or
* the cpu - space pointer to a buffer that may be used to perform DMA to the
* specified device . Such cpu - space buffers are returned along with the DMA
* address ( through the pointer provided ) .
*
* These buffers are used with URB_NO_xxx_DMA_MAP set in urb - > transfer_flags
2007-07-02 10:33:12 +04:00
* to avoid behaviors like using " DMA bounce buffers " , or thrashing IOMMU
* hardware during URB completion / resubmit . The implementation varies between
2005-04-17 02:20:36 +04:00
* platforms , depending on details of how DMA will work to this device .
2007-07-02 10:33:12 +04:00
* Using these buffers also eliminates cacheline sharing problems on
* architectures where CPU caches are not DMA - coherent . On systems without
* bus - snooping caches , these buffers are uncached .
2005-04-17 02:20:36 +04:00
*
* When the buffer is no longer used , free it with usb_buffer_free ( ) .
*/
2008-01-31 02:21:33 +03:00
void * usb_buffer_alloc ( struct usb_device * dev , size_t size , gfp_t mem_flags ,
dma_addr_t * dma )
2005-04-17 02:20:36 +04:00
{
2006-08-30 19:27:36 +04:00
if ( ! dev | | ! dev - > bus )
2005-04-17 02:20:36 +04:00
return NULL ;
2007-01-23 23:55:28 +03:00
return hcd_buffer_alloc ( dev - > bus , size , mem_flags , dma ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_buffer_alloc ) ;
2005-04-17 02:20:36 +04:00
/**
* usb_buffer_free - free memory allocated with usb_buffer_alloc ( )
* @ dev : device the buffer was used with
* @ size : requested buffer size
* @ addr : CPU address of buffer
* @ dma : DMA address of buffer
*
* This reclaims an I / O buffer , letting it be reused . The memory must have
* been allocated using usb_buffer_alloc ( ) , and the parameters must match
2007-07-02 10:33:12 +04:00
* those provided in that allocation request .
2005-04-17 02:20:36 +04:00
*/
2008-01-31 02:21:33 +03:00
void usb_buffer_free ( struct usb_device * dev , size_t size , void * addr ,
dma_addr_t dma )
2005-04-17 02:20:36 +04:00
{
2006-08-30 19:27:36 +04:00
if ( ! dev | | ! dev - > bus )
2006-08-02 06:33:34 +04:00
return ;
if ( ! addr )
return ;
2007-01-23 23:55:28 +03:00
hcd_buffer_free ( dev - > bus , size , addr , dma ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_buffer_free ) ;
2005-04-17 02:20:36 +04:00
/**
* usb_buffer_map - create DMA mapping ( s ) for an urb
* @ urb : urb whose transfer_buffer / setup_packet will be mapped
*
* Return value is either null ( indicating no buffer could be mapped ) , or
* the parameter . URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP are
* added to urb - > transfer_flags if the operation succeeds . If the device
* is connected to this system through a non - DMA controller , this operation
* always succeeds .
*
* This call would normally be used for an urb which is reused , perhaps
* as the target of a large periodic transfer , with usb_buffer_dmasync ( )
* calls to synchronize memory and dma state .
*
* Reverse the effect of this call with usb_buffer_unmap ( ) .
*/
#if 0
2007-01-23 23:55:28 +03:00
struct urb * usb_buffer_map ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
struct usb_bus * bus ;
struct device * controller ;
if ( ! urb
| | ! urb - > dev
| | ! ( bus = urb - > dev - > bus )
| | ! ( controller = bus - > controller ) )
return NULL ;
if ( controller - > dma_mask ) {
2007-01-23 23:55:28 +03:00
urb - > transfer_dma = dma_map_single ( controller ,
2005-04-17 02:20:36 +04:00
urb - > transfer_buffer , urb - > transfer_buffer_length ,
2007-01-23 23:55:28 +03:00
usb_pipein ( urb - > pipe )
2005-04-17 02:20:36 +04:00
? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
2007-01-23 23:55:28 +03:00
if ( usb_pipecontrol ( urb - > pipe ) )
urb - > setup_dma = dma_map_single ( controller ,
2005-04-17 02:20:36 +04:00
urb - > setup_packet ,
2007-01-23 23:55:28 +03:00
sizeof ( struct usb_ctrlrequest ) ,
2005-04-17 02:20:36 +04:00
DMA_TO_DEVICE ) ;
2008-01-31 02:21:33 +03:00
/* FIXME generic api broken like pci, can't report errors */
/* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */
2005-04-17 02:20:36 +04:00
} else
urb - > transfer_dma = ~ 0 ;
urb - > transfer_flags | = ( URB_NO_TRANSFER_DMA_MAP
| URB_NO_SETUP_DMA_MAP ) ;
return urb ;
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_buffer_map ) ;
2005-04-17 02:20:36 +04:00
# endif /* 0 */
/* XXX DISABLED, no users currently. If you wish to re-enable this
* XXX please determine whether the sync is to transfer ownership of
* XXX the buffer from device to cpu or vice verse , and thusly use the
* XXX appropriate _for_ { cpu , device } ( ) method . - DaveM
*/
#if 0
/**
* usb_buffer_dmasync - synchronize DMA and CPU view of buffer ( s )
* @ urb : urb whose transfer_buffer / setup_packet will be synchronized
*/
2007-01-23 23:55:28 +03:00
void usb_buffer_dmasync ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
struct usb_bus * bus ;
struct device * controller ;
if ( ! urb
| | ! ( urb - > transfer_flags & URB_NO_TRANSFER_DMA_MAP )
| | ! urb - > dev
| | ! ( bus = urb - > dev - > bus )
| | ! ( controller = bus - > controller ) )
return ;
if ( controller - > dma_mask ) {
2009-05-28 05:10:44 +04:00
dma_sync_single_for_cpu ( controller ,
2005-04-17 02:20:36 +04:00
urb - > transfer_dma , urb - > transfer_buffer_length ,
2007-01-23 23:55:28 +03:00
usb_pipein ( urb - > pipe )
2005-04-17 02:20:36 +04:00
? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
2007-01-23 23:55:28 +03:00
if ( usb_pipecontrol ( urb - > pipe ) )
2009-05-28 05:10:44 +04:00
dma_sync_single_for_cpu ( controller ,
2005-04-17 02:20:36 +04:00
urb - > setup_dma ,
2007-01-23 23:55:28 +03:00
sizeof ( struct usb_ctrlrequest ) ,
2005-04-17 02:20:36 +04:00
DMA_TO_DEVICE ) ;
}
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_buffer_dmasync ) ;
2005-04-17 02:20:36 +04:00
# endif
/**
* usb_buffer_unmap - free DMA mapping ( s ) for an urb
* @ urb : urb whose transfer_buffer will be unmapped
*
* Reverses the effect of usb_buffer_map ( ) .
*/
#if 0
2007-01-23 23:55:28 +03:00
void usb_buffer_unmap ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
struct usb_bus * bus ;
struct device * controller ;
if ( ! urb
| | ! ( urb - > transfer_flags & URB_NO_TRANSFER_DMA_MAP )
| | ! urb - > dev
| | ! ( bus = urb - > dev - > bus )
| | ! ( controller = bus - > controller ) )
return ;
if ( controller - > dma_mask ) {
2007-01-23 23:55:28 +03:00
dma_unmap_single ( controller ,
2005-04-17 02:20:36 +04:00
urb - > transfer_dma , urb - > transfer_buffer_length ,
2007-01-23 23:55:28 +03:00
usb_pipein ( urb - > pipe )
2005-04-17 02:20:36 +04:00
? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
2007-01-23 23:55:28 +03:00
if ( usb_pipecontrol ( urb - > pipe ) )
dma_unmap_single ( controller ,
2005-04-17 02:20:36 +04:00
urb - > setup_dma ,
2007-01-23 23:55:28 +03:00
sizeof ( struct usb_ctrlrequest ) ,
2005-04-17 02:20:36 +04:00
DMA_TO_DEVICE ) ;
}
urb - > transfer_flags & = ~ ( URB_NO_TRANSFER_DMA_MAP
| URB_NO_SETUP_DMA_MAP ) ;
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_buffer_unmap ) ;
2005-04-17 02:20:36 +04:00
# endif /* 0 */
/**
* usb_buffer_map_sg - create scatterlist DMA mapping ( s ) for an endpoint
* @ dev : device to which the scatterlist will be mapped
2007-07-31 01:07:21 +04:00
* @ is_in : mapping transfer direction
2005-04-17 02:20:36 +04:00
* @ sg : the scatterlist to map
* @ nents : the number of entries in the scatterlist
*
* Return value is either < 0 ( indicating no buffers could be mapped ) , or
* the number of DMA mapping array entries in the scatterlist .
*
* The caller is responsible for placing the resulting DMA addresses from
* the scatterlist into URB transfer buffer pointers , and for setting the
* URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs .
*
* Top I / O rates come from queuing URBs , instead of waiting for each one
* to complete before starting the next I / O . This is particularly easy
* to do with scatterlists . Just allocate and submit one URB for each DMA
* mapping entry returned , stopping on the first error or when all succeed .
* Better yet , use the usb_sg_ * ( ) calls , which do that ( and more ) for you .
*
* This call would normally be used when translating scatterlist requests ,
* rather than usb_buffer_map ( ) , since on some hardware ( with IOMMUs ) it
* may be able to coalesce mappings for improved I / O efficiency .
*
* Reverse the effect of this call with usb_buffer_unmap_sg ( ) .
*/
2007-07-31 01:07:21 +04:00
int usb_buffer_map_sg ( const struct usb_device * dev , int is_in ,
2006-08-27 06:48:11 +04:00
struct scatterlist * sg , int nents )
2005-04-17 02:20:36 +04:00
{
struct usb_bus * bus ;
struct device * controller ;
if ( ! dev
| | ! ( bus = dev - > bus )
| | ! ( controller = bus - > controller )
| | ! controller - > dma_mask )
2009-08-22 22:24:49 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2008-01-31 02:21:33 +03:00
/* FIXME generic api broken like pci, can't report errors */
2007-01-23 23:55:28 +03:00
return dma_map_sg ( controller , sg , nents ,
2009-08-22 22:24:49 +04:00
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ? : - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_buffer_map_sg ) ;
2005-04-17 02:20:36 +04:00
/* XXX DISABLED, no users currently. If you wish to re-enable this
* XXX please determine whether the sync is to transfer ownership of
* XXX the buffer from device to cpu or vice verse , and thusly use the
* XXX appropriate _for_ { cpu , device } ( ) method . - DaveM
*/
#if 0
/**
* usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer ( s )
* @ dev : device to which the scatterlist will be mapped
2007-07-31 01:07:21 +04:00
* @ is_in : mapping transfer direction
2005-04-17 02:20:36 +04:00
* @ sg : the scatterlist to synchronize
* @ n_hw_ents : the positive return value from usb_buffer_map_sg
*
* Use this when you are re - using a scatterlist ' s data buffers for
* another USB request .
*/
2007-07-31 01:07:21 +04:00
void usb_buffer_dmasync_sg ( const struct usb_device * dev , int is_in ,
2006-08-27 06:48:11 +04:00
struct scatterlist * sg , int n_hw_ents )
2005-04-17 02:20:36 +04:00
{
struct usb_bus * bus ;
struct device * controller ;
if ( ! dev
| | ! ( bus = dev - > bus )
| | ! ( controller = bus - > controller )
| | ! controller - > dma_mask )
return ;
2009-05-28 05:10:44 +04:00
dma_sync_sg_for_cpu ( controller , sg , n_hw_ents ,
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_buffer_dmasync_sg ) ;
2005-04-17 02:20:36 +04:00
# endif
/**
* usb_buffer_unmap_sg - free DMA mapping ( s ) for a scatterlist
* @ dev : device to which the scatterlist will be mapped
2007-07-31 01:07:21 +04:00
* @ is_in : mapping transfer direction
2005-04-17 02:20:36 +04:00
* @ sg : the scatterlist to unmap
* @ n_hw_ents : the positive return value from usb_buffer_map_sg
*
* Reverses the effect of usb_buffer_map_sg ( ) .
*/
2007-07-31 01:07:21 +04:00
void usb_buffer_unmap_sg ( const struct usb_device * dev , int is_in ,
2006-08-27 06:48:11 +04:00
struct scatterlist * sg , int n_hw_ents )
2005-04-17 02:20:36 +04:00
{
struct usb_bus * bus ;
struct device * controller ;
if ( ! dev
| | ! ( bus = dev - > bus )
| | ! ( controller = bus - > controller )
| | ! controller - > dma_mask )
return ;
2007-01-23 23:55:28 +03:00
dma_unmap_sg ( controller , sg , n_hw_ents ,
2007-07-31 01:07:21 +04:00
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_buffer_unmap_sg ) ;
2005-04-17 02:20:36 +04:00
2008-11-22 05:31:06 +03:00
/* To disable USB, kernel command line is 'nousb' not 'usbcore.nousb' */
# ifdef MODULE
module_param ( nousb , bool , 0444 ) ;
# else
core_param ( nousb , nousb , bool , 0444 ) ;
# endif
2005-04-17 02:20:36 +04:00
/*
* for external read access to < nousb >
*/
int usb_disabled ( void )
{
return nousb ;
}
2008-01-25 20:12:21 +03:00
EXPORT_SYMBOL_GPL ( usb_disabled ) ;
2005-04-17 02:20:36 +04:00
2008-12-05 22:10:34 +03:00
/*
* Notifications of device and interface registration
*/
static int usb_bus_notify ( struct notifier_block * nb , unsigned long action ,
void * data )
{
struct device * dev = data ;
switch ( action ) {
case BUS_NOTIFY_ADD_DEVICE :
if ( dev - > type = = & usb_device_type )
( void ) usb_create_sysfs_dev_files ( to_usb_device ( dev ) ) ;
else if ( dev - > type = = & usb_if_device_type )
( void ) usb_create_sysfs_intf_files (
to_usb_interface ( dev ) ) ;
break ;
case BUS_NOTIFY_DEL_DEVICE :
if ( dev - > type = = & usb_device_type )
usb_remove_sysfs_dev_files ( to_usb_device ( dev ) ) ;
else if ( dev - > type = = & usb_if_device_type )
usb_remove_sysfs_intf_files ( to_usb_interface ( dev ) ) ;
break ;
}
return 0 ;
}
static struct notifier_block usb_bus_nb = {
. notifier_call = usb_bus_notify ,
} ;
2009-04-25 01:56:26 +04:00
struct dentry * usb_debug_root ;
EXPORT_SYMBOL_GPL ( usb_debug_root ) ;
2009-04-25 02:16:04 +04:00
struct dentry * usb_debug_devices ;
2009-04-25 01:56:26 +04:00
static int usb_debugfs_init ( void )
{
usb_debug_root = debugfs_create_dir ( " usb " , NULL ) ;
if ( ! usb_debug_root )
return - ENOENT ;
2009-04-25 02:16:04 +04:00
usb_debug_devices = debugfs_create_file ( " devices " , 0444 ,
usb_debug_root , NULL ,
& usbfs_devices_fops ) ;
if ( ! usb_debug_devices ) {
debugfs_remove ( usb_debug_root ) ;
usb_debug_root = NULL ;
return - ENOENT ;
}
2009-04-25 01:56:26 +04:00
return 0 ;
}
static void usb_debugfs_cleanup ( void )
{
2009-04-25 02:16:04 +04:00
debugfs_remove ( usb_debug_devices ) ;
2009-04-25 01:56:26 +04:00
debugfs_remove ( usb_debug_root ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Init
*/
static int __init usb_init ( void )
{
int retval ;
if ( nousb ) {
2007-01-23 23:55:28 +03:00
pr_info ( " %s: USB support disabled \n " , usbcore_name ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-04-25 01:56:26 +04:00
retval = usb_debugfs_init ( ) ;
if ( retval )
goto out ;
2006-09-19 18:14:07 +04:00
retval = ksuspend_usb_init ( ) ;
if ( retval )
goto out ;
2005-04-17 02:20:36 +04:00
retval = bus_register ( & usb_bus_type ) ;
2008-01-31 02:21:33 +03:00
if ( retval )
2006-09-19 18:14:07 +04:00
goto bus_register_failed ;
2008-12-05 22:10:34 +03:00
retval = bus_register_notifier ( & usb_bus_type , & usb_bus_nb ) ;
if ( retval )
goto bus_notifier_failed ;
2005-04-17 02:20:36 +04:00
retval = usb_major_init ( ) ;
if ( retval )
goto major_init_failed ;
2005-07-31 03:05:53 +04:00
retval = usb_register ( & usbfs_driver ) ;
if ( retval )
goto driver_register_failed ;
2007-03-13 17:59:31 +03:00
retval = usb_devio_init ( ) ;
2005-07-31 03:05:53 +04:00
if ( retval )
2007-03-13 17:59:31 +03:00
goto usb_devio_init_failed ;
2005-04-17 02:20:36 +04:00
retval = usbfs_init ( ) ;
if ( retval )
goto fs_init_failed ;
retval = usb_hub_init ( ) ;
if ( retval )
goto hub_init_failed ;
2006-07-02 06:08:49 +04:00
retval = usb_register_device_driver ( & usb_generic_driver , THIS_MODULE ) ;
2005-04-17 02:20:36 +04:00
if ( ! retval )
goto out ;
usb_hub_cleanup ( ) ;
hub_init_failed :
usbfs_cleanup ( ) ;
fs_init_failed :
2007-03-13 17:59:31 +03:00
usb_devio_cleanup ( ) ;
usb_devio_init_failed :
2005-07-31 03:05:53 +04:00
usb_deregister ( & usbfs_driver ) ;
driver_register_failed :
usb_major_cleanup ( ) ;
2005-04-17 02:20:36 +04:00
major_init_failed :
2008-12-05 22:10:34 +03:00
bus_unregister_notifier ( & usb_bus_type , & usb_bus_nb ) ;
bus_notifier_failed :
2005-04-17 02:20:36 +04:00
bus_unregister ( & usb_bus_type ) ;
2006-09-19 18:14:07 +04:00
bus_register_failed :
ksuspend_usb_cleanup ( ) ;
2005-04-17 02:20:36 +04:00
out :
return retval ;
}
/*
* Cleanup
*/
static void __exit usb_exit ( void )
{
/* This will matter if shutdown/reboot does exitcalls. */
if ( nousb )
return ;
2006-07-02 06:08:49 +04:00
usb_deregister_device_driver ( & usb_generic_driver ) ;
2005-04-17 02:20:36 +04:00
usb_major_cleanup ( ) ;
usbfs_cleanup ( ) ;
2005-07-31 03:05:53 +04:00
usb_deregister ( & usbfs_driver ) ;
2007-03-13 17:59:31 +03:00
usb_devio_cleanup ( ) ;
2005-04-17 02:20:36 +04:00
usb_hub_cleanup ( ) ;
2008-12-05 22:10:34 +03:00
bus_unregister_notifier ( & usb_bus_type , & usb_bus_nb ) ;
2005-04-17 02:20:36 +04:00
bus_unregister ( & usb_bus_type ) ;
2006-09-19 18:14:07 +04:00
ksuspend_usb_cleanup ( ) ;
2009-04-25 01:56:26 +04:00
usb_debugfs_cleanup ( ) ;
2005-04-17 02:20:36 +04:00
}
subsys_initcall ( usb_init ) ;
module_exit ( usb_exit ) ;
MODULE_LICENSE ( " GPL " ) ;