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>
# 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/smp_lock.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>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# include <asm/scatterlist.h>
# 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 */
2006-09-19 18:14:07 +04:00
struct workqueue_struct * ksuspend_usb_wq ; /* For autosuspend */
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 ;
}
/**
* usb_altnum_to_altsetting - get the altsetting structure with a given
* alternate setting number .
* @ 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 !
*/
2006-08-27 06:48:11 +04: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 ;
}
2005-12-22 04:24:54 +03:00
struct find_interface_arg {
int minor ;
struct usb_interface * interface ;
} ;
2005-04-17 02:20:36 +04:00
2005-03-21 22:09:40 +03:00
static int __find_interface ( struct device * dev , void * data )
{
2005-12-22 04:24:54 +03:00
struct find_interface_arg * arg = data ;
struct usb_interface * intf ;
2005-03-21 22:09:40 +03:00
/* can't look at usb devices, only interfaces */
2006-07-02 06:08:49 +04:00
if ( is_usb_device ( dev ) )
2005-03-21 22:09:40 +03:00
return 0 ;
intf = to_usb_interface ( dev ) ;
2005-12-22 04:24:54 +03:00
if ( intf - > minor ! = - 1 & & intf - > minor = = arg - > minor ) {
arg - > interface = intf ;
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
*
* This walks the driver device list and returns a pointer to the interface
* 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 )
{
2005-12-22 04:24:54 +03:00
struct find_interface_arg argb ;
2006-08-28 22:43:25 +04:00
int retval ;
2005-04-17 02:20:36 +04:00
2005-12-22 04:24:54 +03:00
argb . minor = minor ;
argb . interface = NULL ;
2006-08-28 22:43:25 +04:00
/* eat the error, it will be in argb.interface */
retval = driver_for_each_device ( & drv - > drvwrap . driver , NULL , & argb ,
__find_interface ) ;
2005-12-22 04:24:54 +03:00
return argb . 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 ;
udev = to_usb_device ( dev ) ;
2006-09-19 18:14:07 +04:00
# ifdef CONFIG_USB_SUSPEND
2006-08-30 23:47:02 +04:00
cancel_delayed_work ( & udev - > autosuspend ) ;
2006-09-19 18:14:07 +04:00
flush_workqueue ( ksuspend_usb_wq ) ;
2006-08-30 23:47:02 +04:00
# endif
2005-04-17 02:20:36 +04:00
usb_destroy_configuration ( udev ) ;
2006-08-30 19:32:52 +04:00
usb_put_hcd ( bus_to_hcd ( udev - > bus ) ) ;
2005-04-17 02:20:36 +04:00
kfree ( udev - > product ) ;
kfree ( udev - > manufacturer ) ;
kfree ( udev - > serial ) ;
kfree ( udev ) ;
}
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 )
{
ksuspend_usb_wq = create_singlethread_workqueue ( " ksuspend_usbd " ) ;
if ( ! ksuspend_usb_wq )
return - ENOMEM ;
return 0 ;
}
static void ksuspend_usb_cleanup ( void )
{
destroy_workqueue ( ksuspend_usb_wq ) ;
}
# else
# define ksuspend_usb_init() 0
# define ksuspend_usb_cleanup() do {} while (0)
# endif
# ifdef CONFIG_USB_SUSPEND
2006-08-30 23:47:02 +04:00
/* usb_autosuspend_work - callback routine to autosuspend a USB device */
static void usb_autosuspend_work ( void * _udev )
{
struct usb_device * udev = _udev ;
2006-09-26 22:50:20 +04:00
usb_pm_lock ( udev ) ;
2006-08-30 23:47:02 +04:00
udev - > auto_pm = 1 ;
usb_suspend_both ( udev , PMSG_SUSPEND ) ;
2006-09-26 22:50:20 +04:00
usb_pm_unlock ( udev ) ;
2006-08-30 23:47:02 +04:00
}
2006-09-19 18:14:07 +04:00
# else
static void usb_autosuspend_work ( void * _udev )
{ }
2006-08-30 23:47:02 +04:00
# endif
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
* Context : ! in_interrupt ( )
*
* 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 .
*/
struct usb_device *
usb_alloc_dev ( struct usb_device * parent , struct usb_bus * bus , unsigned port1 )
{
struct usb_device * dev ;
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 ;
}
device_initialize ( & dev - > dev ) ;
dev - > dev . bus = & usb_bus_type ;
dev - > dev . dma_mask = bus - > controller - > dma_mask ;
dev - > dev . release = usb_release_dev ;
dev - > state = USB_STATE_ATTACHED ;
2006-07-02 06:08:49 +04:00
/* This magic assignment distinguishes devices from interfaces */
dev - > dev . platform_data = & usb_generic_driver ;
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 */
dev - > ep_in [ 0 ] = dev - > ep_out [ 0 ] = & dev - > ep0 ;
/* 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
* are often labeled with these port numbers . The bus_id isn ' t
* as stable : bus - > busnum changes easily from modprobe order ,
* cardbus or pci hotplugging , and so on .
*/
if ( unlikely ( ! parent ) ) {
dev - > devpath [ 0 ] = ' 0 ' ;
dev - > dev . parent = bus - > controller ;
sprintf ( & dev - > dev . bus_id [ 0 ] , " usb%d " , bus - > busnum ) ;
} else {
/* match any labeling on the hubs; it's one-based */
if ( parent - > devpath [ 0 ] = = ' 0 ' )
snprintf ( dev - > devpath , sizeof dev - > devpath ,
" %d " , port1 ) ;
else
snprintf ( dev - > devpath , sizeof dev - > devpath ,
" %s.%d " , parent - > devpath , port1 ) ;
dev - > dev . parent = & parent - > dev ;
sprintf ( & dev - > dev . bus_id [ 0 ] , " %d-%s " ,
bus - > busnum , dev - > devpath ) ;
/* 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 ) ;
INIT_WORK ( & dev - > autosuspend , usb_autosuspend_work , dev ) ;
# endif
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 ;
}
/**
* 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 ) ;
}
/**
* 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 ;
}
/**
* 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 ) ;
}
/* 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 .
*/
/**
* usb_lock_device_for_reset - cautiously acquire the lock for a
* usb device structure
* @ 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
*
* Returns a negative error code for failure , otherwise 1 or 0 to indicate
* that the device will or will not have to be unlocked . ( 0 can be
* returned when an interface is given and is BINDING , because in that
* case the driver already owns the device lock . )
*/
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 ;
if ( iface ) {
switch ( iface - > condition ) {
case USB_INTERFACE_BINDING :
return 0 ;
case USB_INTERFACE_BOUND :
break ;
default :
return - EINTR ;
}
}
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 ;
if ( iface & & iface - > condition ! = USB_INTERFACE_BOUND )
return - EINTR ;
}
return 1 ;
}
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 ) ) ) {
dev_dbg ( & dev - > dev , " matched this device! \n " ) ;
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 ;
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 ;
buslist ! = & usb_bus_list ;
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 )
{
2006-08-30 19:27:36 +04:00
return usb_hcd_get_frame_number ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2006-09-27 22:58:53 +04:00
/**
* usb_endpoint_dir_in - check if the endpoint has IN direction
* @ epd : endpoint to be checked
*
* Returns true if the endpoint is of type IN , otherwise it returns false .
*/
int usb_endpoint_dir_in ( const struct usb_endpoint_descriptor * epd )
{
return ( ( epd - > bEndpointAddress & USB_ENDPOINT_DIR_MASK ) = = USB_DIR_IN ) ;
}
/**
* usb_endpoint_dir_out - check if the endpoint has OUT direction
* @ epd : endpoint to be checked
*
* Returns true if the endpoint is of type OUT , otherwise it returns false .
*/
int usb_endpoint_dir_out ( const struct usb_endpoint_descriptor * epd )
{
return ( ( epd - > bEndpointAddress & USB_ENDPOINT_DIR_MASK ) = = USB_DIR_OUT ) ;
}
/**
* usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type
* @ epd : endpoint to be checked
*
* Returns true if the endpoint is of type bulk , otherwise it returns false .
*/
int usb_endpoint_xfer_bulk ( const struct usb_endpoint_descriptor * epd )
{
return ( ( epd - > bmAttributes & USB_ENDPOINT_XFERTYPE_MASK ) = =
USB_ENDPOINT_XFER_BULK ) ;
}
/**
* usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
* @ epd : endpoint to be checked
*
* Returns true if the endpoint is of type interrupt , otherwise it returns
* false .
*/
int usb_endpoint_xfer_int ( const struct usb_endpoint_descriptor * epd )
{
return ( ( epd - > bmAttributes & USB_ENDPOINT_XFERTYPE_MASK ) = =
USB_ENDPOINT_XFER_INT ) ;
}
/**
* usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type
* @ epd : endpoint to be checked
*
* Returns true if the endpoint is of type isochronous , otherwise it returns
* false .
*/
int usb_endpoint_xfer_isoc ( const struct usb_endpoint_descriptor * epd )
{
return ( ( epd - > bmAttributes & USB_ENDPOINT_XFERTYPE_MASK ) = =
USB_ENDPOINT_XFER_ISOC ) ;
}
/**
* usb_endpoint_is_bulk_in - check if the endpoint is bulk IN
* @ epd : endpoint to be checked
*
* Returns true if the endpoint has bulk transfer type and IN direction ,
* otherwise it returns false .
*/
int usb_endpoint_is_bulk_in ( const struct usb_endpoint_descriptor * epd )
{
return ( usb_endpoint_xfer_bulk ( epd ) & & usb_endpoint_dir_in ( epd ) ) ;
}
/**
* usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT
* @ epd : endpoint to be checked
*
* Returns true if the endpoint has bulk transfer type and OUT direction ,
* otherwise it returns false .
*/
int usb_endpoint_is_bulk_out ( const struct usb_endpoint_descriptor * epd )
{
return ( usb_endpoint_xfer_bulk ( epd ) & & usb_endpoint_dir_out ( epd ) ) ;
}
/**
* usb_endpoint_is_int_in - check if the endpoint is interrupt IN
* @ epd : endpoint to be checked
*
* Returns true if the endpoint has interrupt transfer type and IN direction ,
* otherwise it returns false .
*/
int usb_endpoint_is_int_in ( const struct usb_endpoint_descriptor * epd )
{
return ( usb_endpoint_xfer_int ( epd ) & & usb_endpoint_dir_in ( epd ) ) ;
}
/**
* usb_endpoint_is_int_out - check if the endpoint is interrupt OUT
* @ epd : endpoint to be checked
*
* Returns true if the endpoint has interrupt transfer type and OUT direction ,
* otherwise it returns false .
*/
int usb_endpoint_is_int_out ( const struct usb_endpoint_descriptor * epd )
{
return ( usb_endpoint_xfer_int ( epd ) & & usb_endpoint_dir_out ( epd ) ) ;
}
/**
* usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN
* @ epd : endpoint to be checked
*
* Returns true if the endpoint has isochronous transfer type and IN direction ,
* otherwise it returns false .
*/
int usb_endpoint_is_isoc_in ( const struct usb_endpoint_descriptor * epd )
{
return ( usb_endpoint_xfer_isoc ( epd ) & & usb_endpoint_dir_in ( epd ) ) ;
}
/**
* usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT
* @ epd : endpoint to be checked
*
* Returns true if the endpoint has isochronous transfer type and OUT direction ,
* otherwise it returns false .
*/
int usb_endpoint_is_isoc_out ( const struct usb_endpoint_descriptor * epd )
{
return ( usb_endpoint_xfer_isoc ( epd ) & & usb_endpoint_dir_out ( epd ) ) ;
}
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 ,
unsigned char type , void * * ptr )
{
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 ,
header - > bDescriptorType ,
header - > bLength ) ;
return - 1 ;
}
if ( header - > bDescriptorType = = type ) {
* ptr = header ;
return 0 ;
}
buffer + = header - > bLength ;
size - = header - > bLength ;
}
return - 1 ;
}
/**
* 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
* to avoid behaviors like using " DMA bounce buffers " , or tying down I / O
* mapping hardware for long idle periods . The implementation varies between
* platforms , depending on details of how DMA will work to this device .
* Using these buffers also helps prevent cacheline sharing problems on
* architectures where CPU caches are not DMA - coherent .
*
* When the buffer is no longer used , free it with usb_buffer_free ( ) .
*/
void * usb_buffer_alloc (
struct usb_device * dev ,
size_t size ,
2005-10-21 11:21:58 +04:00
gfp_t mem_flags ,
2005-04-17 02:20:36 +04:00
dma_addr_t * dma
)
{
2006-08-30 19:27:36 +04:00
if ( ! dev | | ! dev - > bus )
2005-04-17 02:20:36 +04:00
return NULL ;
2006-08-30 19:27:36 +04:00
return hcd_buffer_alloc ( dev - > bus , size , mem_flags , dma ) ;
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
* those provided in that allocation request .
*/
void usb_buffer_free (
struct usb_device * dev ,
size_t size ,
void * addr ,
dma_addr_t dma
)
{
2006-08-30 19:27:36 +04:00
if ( ! dev | | ! dev - > bus )
2006-08-02 06:33:34 +04:00
return ;
if ( ! addr )
return ;
2006-08-30 19:27:36 +04:00
hcd_buffer_free ( dev - > bus , size , addr , dma ) ;
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
struct urb * usb_buffer_map ( struct urb * urb )
{
struct usb_bus * bus ;
struct device * controller ;
if ( ! urb
| | ! urb - > dev
| | ! ( bus = urb - > dev - > bus )
| | ! ( controller = bus - > controller ) )
return NULL ;
if ( controller - > dma_mask ) {
urb - > transfer_dma = dma_map_single ( controller ,
urb - > transfer_buffer , urb - > transfer_buffer_length ,
usb_pipein ( urb - > pipe )
? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
if ( usb_pipecontrol ( urb - > pipe ) )
urb - > setup_dma = dma_map_single ( controller ,
urb - > setup_packet ,
sizeof ( struct usb_ctrlrequest ) ,
DMA_TO_DEVICE ) ;
// FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
} else
urb - > transfer_dma = ~ 0 ;
urb - > transfer_flags | = ( URB_NO_TRANSFER_DMA_MAP
| URB_NO_SETUP_DMA_MAP ) ;
return urb ;
}
# 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
*/
void usb_buffer_dmasync ( struct urb * urb )
{
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 ) {
dma_sync_single ( controller ,
urb - > transfer_dma , urb - > transfer_buffer_length ,
usb_pipein ( urb - > pipe )
? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
if ( usb_pipecontrol ( urb - > pipe ) )
dma_sync_single ( controller ,
urb - > setup_dma ,
sizeof ( struct usb_ctrlrequest ) ,
DMA_TO_DEVICE ) ;
}
}
# 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
void usb_buffer_unmap ( struct urb * urb )
{
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 ) {
dma_unmap_single ( controller ,
urb - > transfer_dma , urb - > transfer_buffer_length ,
usb_pipein ( urb - > pipe )
? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
if ( usb_pipecontrol ( urb - > pipe ) )
dma_unmap_single ( controller ,
urb - > setup_dma ,
sizeof ( struct usb_ctrlrequest ) ,
DMA_TO_DEVICE ) ;
}
urb - > transfer_flags & = ~ ( URB_NO_TRANSFER_DMA_MAP
| URB_NO_SETUP_DMA_MAP ) ;
}
# endif /* 0 */
/**
* usb_buffer_map_sg - create scatterlist DMA mapping ( s ) for an endpoint
* @ dev : device to which the scatterlist will be mapped
* @ pipe : endpoint defining the mapping direction
* @ 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 ( ) .
*/
2006-08-27 06:48:11 +04:00
int usb_buffer_map_sg ( const struct usb_device * dev , unsigned pipe ,
struct scatterlist * sg , int nents )
2005-04-17 02:20:36 +04:00
{
struct usb_bus * bus ;
struct device * controller ;
if ( ! dev
| | usb_pipecontrol ( pipe )
| | ! ( bus = dev - > bus )
| | ! ( controller = bus - > controller )
| | ! controller - > dma_mask )
return - 1 ;
// FIXME generic api broken like pci, can't report errors
return dma_map_sg ( controller , sg , nents ,
usb_pipein ( pipe ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
}
/* 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
* @ pipe : endpoint defining the mapping direction
* @ 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 .
*/
2006-08-27 06:48:11 +04:00
void usb_buffer_dmasync_sg ( const struct usb_device * dev , unsigned pipe ,
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 ;
dma_sync_sg ( controller , sg , n_hw_ents ,
usb_pipein ( pipe ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
}
# endif
/**
* usb_buffer_unmap_sg - free DMA mapping ( s ) for a scatterlist
* @ dev : device to which the scatterlist will be mapped
* @ pipe : endpoint defining the mapping direction
* @ 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 ( ) .
*/
2006-08-27 06:48:11 +04:00
void usb_buffer_unmap_sg ( const struct usb_device * dev , unsigned pipe ,
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 ;
dma_unmap_sg ( controller , sg , n_hw_ents ,
usb_pipein ( pipe ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE ) ;
}
/* format to disable USB on kernel command line is: nousb */
2005-12-21 01:15:04 +03:00
__module_param_call ( " " , nousb , param_set_bool , param_get_bool , & nousb , 0444 ) ;
2005-04-17 02:20:36 +04:00
/*
* for external read access to < nousb >
*/
int usb_disabled ( void )
{
return nousb ;
}
/*
* Init
*/
static int __init usb_init ( void )
{
int retval ;
if ( nousb ) {
pr_info ( " %s: USB support disabled \n " , usbcore_name ) ;
return 0 ;
}
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 ) ;
if ( retval )
2006-09-19 18:14:07 +04:00
goto bus_register_failed ;
2005-04-17 02:20:36 +04:00
retval = usb_host_init ( ) ;
if ( retval )
goto host_init_failed ;
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 ;
retval = usbdev_init ( ) ;
if ( retval )
goto usbdevice_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 :
2005-07-31 03:05:53 +04:00
usbdev_cleanup ( ) ;
usbdevice_init_failed :
usb_deregister ( & usbfs_driver ) ;
driver_register_failed :
usb_major_cleanup ( ) ;
2005-04-17 02:20:36 +04:00
major_init_failed :
usb_host_cleanup ( ) ;
host_init_failed :
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 ) ;
usbdev_cleanup ( ) ;
2005-04-17 02:20:36 +04:00
usb_hub_cleanup ( ) ;
usb_host_cleanup ( ) ;
bus_unregister ( & usb_bus_type ) ;
2006-09-19 18:14:07 +04:00
ksuspend_usb_cleanup ( ) ;
2005-04-17 02:20:36 +04:00
}
subsys_initcall ( usb_init ) ;
module_exit ( usb_exit ) ;
/*
* USB may be built into the kernel or be built as modules .
* These symbols are exported for device ( or host controller )
* driver modules to use .
*/
EXPORT_SYMBOL ( usb_disabled ) ;
2005-06-30 03:53:29 +04:00
EXPORT_SYMBOL_GPL ( usb_get_intf ) ;
EXPORT_SYMBOL_GPL ( usb_put_intf ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( usb_put_dev ) ;
EXPORT_SYMBOL ( usb_get_dev ) ;
EXPORT_SYMBOL ( usb_hub_tt_clear_buffer ) ;
EXPORT_SYMBOL ( usb_lock_device_for_reset ) ;
EXPORT_SYMBOL ( usb_find_interface ) ;
EXPORT_SYMBOL ( usb_ifnum_to_if ) ;
EXPORT_SYMBOL ( usb_altnum_to_altsetting ) ;
EXPORT_SYMBOL ( __usb_get_extra_descriptor ) ;
EXPORT_SYMBOL ( usb_find_device ) ;
EXPORT_SYMBOL ( usb_get_current_frame_number ) ;
2006-09-27 22:58:53 +04:00
EXPORT_SYMBOL_GPL ( usb_endpoint_dir_in ) ;
EXPORT_SYMBOL_GPL ( usb_endpoint_dir_out ) ;
EXPORT_SYMBOL_GPL ( usb_endpoint_xfer_bulk ) ;
EXPORT_SYMBOL_GPL ( usb_endpoint_xfer_int ) ;
EXPORT_SYMBOL_GPL ( usb_endpoint_xfer_isoc ) ;
EXPORT_SYMBOL_GPL ( usb_endpoint_is_bulk_in ) ;
EXPORT_SYMBOL_GPL ( usb_endpoint_is_bulk_out ) ;
EXPORT_SYMBOL_GPL ( usb_endpoint_is_int_in ) ;
EXPORT_SYMBOL_GPL ( usb_endpoint_is_int_out ) ;
EXPORT_SYMBOL_GPL ( usb_endpoint_is_isoc_in ) ;
EXPORT_SYMBOL_GPL ( usb_endpoint_is_isoc_out ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( usb_buffer_alloc ) ;
EXPORT_SYMBOL ( usb_buffer_free ) ;
#if 0
EXPORT_SYMBOL ( usb_buffer_map ) ;
EXPORT_SYMBOL ( usb_buffer_dmasync ) ;
EXPORT_SYMBOL ( usb_buffer_unmap ) ;
# endif
EXPORT_SYMBOL ( usb_buffer_map_sg ) ;
#if 0
EXPORT_SYMBOL ( usb_buffer_dmasync_sg ) ;
# endif
EXPORT_SYMBOL ( usb_buffer_unmap_sg ) ;
MODULE_LICENSE ( " GPL " ) ;