2005-04-17 02:20:36 +04:00
# include <linux/usb.h>
2007-06-08 23:23:27 +04:00
# include <linux/usb/ch9.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/device.h>
# include <asm/byteorder.h>
2005-04-19 04:39:24 +04:00
# include "usb.h"
# include "hcd.h"
2005-04-17 02:20:36 +04:00
# define USB_MAXALTSETTING 128 /* Hard limit */
# define USB_MAXENDPOINTS 30 /* Hard limit */
# define USB_MAXCONFIG 8 /* Arbitrary limit */
static inline const char * plural ( int n )
{
return ( n = = 1 ? " " : " s " ) ;
}
static int find_next_descriptor ( unsigned char * buffer , int size ,
int dt1 , int dt2 , int * num_skipped )
{
struct usb_descriptor_header * h ;
int n = 0 ;
unsigned char * buffer0 = buffer ;
/* Find the next descriptor of type dt1 or dt2 */
while ( size > 0 ) {
h = ( struct usb_descriptor_header * ) buffer ;
if ( h - > bDescriptorType = = dt1 | | h - > bDescriptorType = = dt2 )
break ;
buffer + = h - > bLength ;
size - = h - > bLength ;
+ + n ;
}
/* Store the number of descriptors skipped and return the
* number of bytes skipped */
if ( num_skipped )
* num_skipped = n ;
return buffer - buffer0 ;
}
static int usb_parse_endpoint ( struct device * ddev , int cfgno , int inum ,
int asnum , struct usb_host_interface * ifp , int num_ep ,
unsigned char * buffer , int size )
{
unsigned char * buffer0 = buffer ;
struct usb_endpoint_descriptor * d ;
struct usb_host_endpoint * endpoint ;
2007-06-08 23:23:27 +04:00
int n , i , j ;
2005-04-17 02:20:36 +04:00
d = ( struct usb_endpoint_descriptor * ) buffer ;
buffer + = d - > bLength ;
size - = d - > bLength ;
if ( d - > bLength > = USB_DT_ENDPOINT_AUDIO_SIZE )
n = USB_DT_ENDPOINT_AUDIO_SIZE ;
else if ( d - > bLength > = USB_DT_ENDPOINT_SIZE )
n = USB_DT_ENDPOINT_SIZE ;
else {
dev_warn ( ddev , " config %d interface %d altsetting %d has an "
" invalid endpoint descriptor of length %d, skipping \n " ,
cfgno , inum , asnum , d - > bLength ) ;
goto skip_to_next_endpoint_or_interface_descriptor ;
}
i = d - > bEndpointAddress & ~ USB_ENDPOINT_DIR_MASK ;
if ( i > = 16 | | i = = 0 ) {
dev_warn ( ddev , " config %d interface %d altsetting %d has an "
" invalid endpoint with address 0x%X, skipping \n " ,
cfgno , inum , asnum , d - > bEndpointAddress ) ;
goto skip_to_next_endpoint_or_interface_descriptor ;
}
/* Only store as many endpoints as we have room for */
if ( ifp - > desc . bNumEndpoints > = num_ep )
goto skip_to_next_endpoint_or_interface_descriptor ;
endpoint = & ifp - > endpoint [ ifp - > desc . bNumEndpoints ] ;
+ + ifp - > desc . bNumEndpoints ;
memcpy ( & endpoint - > desc , d , n ) ;
INIT_LIST_HEAD ( & endpoint - > urb_list ) ;
2007-06-12 23:47:17 +04:00
/* Fix up bInterval values outside the legal range. Use 32 ms if no
* proper value can be guessed . */
2007-06-08 23:23:27 +04:00
i = 0 ; /* i = min, j = max, n = default */
j = 255 ;
if ( usb_endpoint_xfer_int ( d ) ) {
i = 1 ;
switch ( to_usb_device ( ddev ) - > speed ) {
case USB_SPEED_HIGH :
2007-06-12 23:47:17 +04:00
/* Many device manufacturers are using full-speed
* bInterval values in high - speed interrupt endpoint
* descriptors . Try to fix those and fall back to a
* 32 ms default value otherwise . */
n = fls ( d - > bInterval * 8 ) ;
if ( n = = 0 )
n = 9 ; /* 32 ms = 2^(9-1) uframes */
2007-06-08 23:23:27 +04:00
j = 16 ;
break ;
default : /* USB_SPEED_FULL or _LOW */
/* For low-speed, 10 ms is the official minimum.
* But some " overclocked " devices might want faster
* polling so we ' ll allow it . */
n = 32 ;
break ;
}
} else if ( usb_endpoint_xfer_isoc ( d ) ) {
i = 1 ;
j = 16 ;
switch ( to_usb_device ( ddev ) - > speed ) {
case USB_SPEED_HIGH :
n = 9 ; /* 32 ms = 2^(9-1) uframes */
break ;
default : /* USB_SPEED_FULL */
n = 6 ; /* 32 ms = 2^(6-1) frames */
break ;
}
}
if ( d - > bInterval < i | | d - > bInterval > j ) {
dev_warn ( ddev , " config %d interface %d altsetting %d "
" endpoint 0x%X has an invalid bInterval %d, "
" changing to %d \n " ,
cfgno , inum , asnum ,
d - > bEndpointAddress , d - > bInterval , n ) ;
endpoint - > desc . bInterval = n ;
}
2007-06-08 23:25:02 +04:00
/* Some buggy low-speed devices have Bulk endpoints, which is
* explicitly forbidden by the USB spec . In an attempt to make
* them usable , we will try treating them as Interrupt endpoints .
*/
if ( to_usb_device ( ddev ) - > speed = = USB_SPEED_LOW & &
usb_endpoint_xfer_bulk ( d ) ) {
dev_warn ( ddev , " config %d interface %d altsetting %d "
" endpoint 0x%X is Bulk; changing to Interrupt \n " ,
cfgno , inum , asnum , d - > bEndpointAddress ) ;
endpoint - > desc . bmAttributes = USB_ENDPOINT_XFER_INT ;
endpoint - > desc . bInterval = 1 ;
if ( le16_to_cpu ( endpoint - > desc . wMaxPacketSize ) > 8 )
endpoint - > desc . wMaxPacketSize = cpu_to_le16 ( 8 ) ;
}
2005-04-17 02:20:36 +04:00
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the next endpoint or interface descriptor */
endpoint - > extra = buffer ;
i = find_next_descriptor ( buffer , size , USB_DT_ENDPOINT ,
USB_DT_INTERFACE , & n ) ;
endpoint - > extralen = i ;
if ( n > 0 )
dev_dbg ( ddev , " skipped %d descriptor%s after %s \n " ,
n , plural ( n ) , " endpoint " ) ;
return buffer - buffer0 + i ;
skip_to_next_endpoint_or_interface_descriptor :
i = find_next_descriptor ( buffer , size , USB_DT_ENDPOINT ,
USB_DT_INTERFACE , NULL ) ;
return buffer - buffer0 + i ;
}
void usb_release_interface_cache ( struct kref * ref )
{
struct usb_interface_cache * intfc = ref_to_usb_interface_cache ( ref ) ;
int j ;
2005-10-25 00:24:14 +04:00
for ( j = 0 ; j < intfc - > num_altsetting ; j + + ) {
struct usb_host_interface * alt = & intfc - > altsetting [ j ] ;
kfree ( alt - > endpoint ) ;
kfree ( alt - > string ) ;
}
2005-04-17 02:20:36 +04:00
kfree ( intfc ) ;
}
static int usb_parse_interface ( struct device * ddev , int cfgno ,
struct usb_host_config * config , unsigned char * buffer , int size ,
u8 inums [ ] , u8 nalts [ ] )
{
unsigned char * buffer0 = buffer ;
struct usb_interface_descriptor * d ;
int inum , asnum ;
struct usb_interface_cache * intfc ;
struct usb_host_interface * alt ;
int i , n ;
int len , retval ;
int num_ep , num_ep_orig ;
d = ( struct usb_interface_descriptor * ) buffer ;
buffer + = d - > bLength ;
size - = d - > bLength ;
if ( d - > bLength < USB_DT_INTERFACE_SIZE )
goto skip_to_next_interface_descriptor ;
/* Which interface entry is this? */
intfc = NULL ;
inum = d - > bInterfaceNumber ;
for ( i = 0 ; i < config - > desc . bNumInterfaces ; + + i ) {
if ( inums [ i ] = = inum ) {
intfc = config - > intf_cache [ i ] ;
break ;
}
}
if ( ! intfc | | intfc - > num_altsetting > = nalts [ i ] )
goto skip_to_next_interface_descriptor ;
/* Check for duplicate altsetting entries */
asnum = d - > bAlternateSetting ;
for ( ( i = 0 , alt = & intfc - > altsetting [ 0 ] ) ;
i < intfc - > num_altsetting ;
( + + i , + + alt ) ) {
if ( alt - > desc . bAlternateSetting = = asnum ) {
dev_warn ( ddev , " Duplicate descriptor for config %d "
" interface %d altsetting %d, skipping \n " ,
cfgno , inum , asnum ) ;
goto skip_to_next_interface_descriptor ;
}
}
+ + intfc - > num_altsetting ;
memcpy ( & alt - > desc , d , USB_DT_INTERFACE_SIZE ) ;
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the first endpoint or interface descriptor */
alt - > extra = buffer ;
i = find_next_descriptor ( buffer , size , USB_DT_ENDPOINT ,
USB_DT_INTERFACE , & n ) ;
alt - > extralen = i ;
if ( n > 0 )
dev_dbg ( ddev , " skipped %d descriptor%s after %s \n " ,
n , plural ( n ) , " interface " ) ;
buffer + = i ;
size - = i ;
/* Allocate space for the right(?) number of endpoints */
num_ep = num_ep_orig = alt - > desc . bNumEndpoints ;
alt - > desc . bNumEndpoints = 0 ; // Use as a counter
if ( num_ep > USB_MAXENDPOINTS ) {
dev_warn ( ddev , " too many endpoints for config %d interface %d "
" altsetting %d: %d, using maximum allowed: %d \n " ,
cfgno , inum , asnum , num_ep , USB_MAXENDPOINTS ) ;
num_ep = USB_MAXENDPOINTS ;
}
2007-05-16 01:40:37 +04:00
if ( num_ep > 0 ) { /* Can't allocate 0 bytes */
len = sizeof ( struct usb_host_endpoint ) * num_ep ;
alt - > endpoint = kzalloc ( len , GFP_KERNEL ) ;
if ( ! alt - > endpoint )
return - ENOMEM ;
}
2005-04-17 02:20:36 +04:00
/* Parse all the endpoint descriptors */
n = 0 ;
while ( size > 0 ) {
if ( ( ( struct usb_descriptor_header * ) buffer ) - > bDescriptorType
= = USB_DT_INTERFACE )
break ;
retval = usb_parse_endpoint ( ddev , cfgno , inum , asnum , alt ,
num_ep , buffer , size ) ;
if ( retval < 0 )
return retval ;
+ + n ;
buffer + = retval ;
size - = retval ;
}
if ( n ! = num_ep_orig )
dev_warn ( ddev , " config %d interface %d altsetting %d has %d "
" endpoint descriptor%s, different from the interface "
" descriptor's value: %d \n " ,
cfgno , inum , asnum , n , plural ( n ) , num_ep_orig ) ;
return buffer - buffer0 ;
skip_to_next_interface_descriptor :
i = find_next_descriptor ( buffer , size , USB_DT_INTERFACE ,
USB_DT_INTERFACE , NULL ) ;
return buffer - buffer0 + i ;
}
static int usb_parse_configuration ( struct device * ddev , int cfgidx ,
struct usb_host_config * config , unsigned char * buffer , int size )
{
unsigned char * buffer0 = buffer ;
int cfgno ;
int nintf , nintf_orig ;
int i , j , n ;
struct usb_interface_cache * intfc ;
unsigned char * buffer2 ;
int size2 ;
struct usb_descriptor_header * header ;
int len , retval ;
u8 inums [ USB_MAXINTERFACES ] , nalts [ USB_MAXINTERFACES ] ;
memcpy ( & config - > desc , buffer , USB_DT_CONFIG_SIZE ) ;
if ( config - > desc . bDescriptorType ! = USB_DT_CONFIG | |
config - > desc . bLength < USB_DT_CONFIG_SIZE ) {
dev_err ( ddev , " invalid descriptor for config index %d: "
" type = 0x%X, length = %d \n " , cfgidx ,
config - > desc . bDescriptorType , config - > desc . bLength ) ;
return - EINVAL ;
}
cfgno = config - > desc . bConfigurationValue ;
buffer + = config - > desc . bLength ;
size - = config - > desc . bLength ;
nintf = nintf_orig = config - > desc . bNumInterfaces ;
if ( nintf > USB_MAXINTERFACES ) {
dev_warn ( ddev , " config %d has too many interfaces: %d, "
" using maximum allowed: %d \n " ,
cfgno , nintf , USB_MAXINTERFACES ) ;
nintf = USB_MAXINTERFACES ;
}
/* Go through the descriptors, checking their length and counting the
* number of altsettings for each interface */
n = 0 ;
for ( ( buffer2 = buffer , size2 = size ) ;
size2 > 0 ;
( buffer2 + = header - > bLength , size2 - = header - > bLength ) ) {
if ( size2 < sizeof ( struct usb_descriptor_header ) ) {
dev_warn ( ddev , " config %d descriptor has %d excess "
" byte%s, ignoring \n " ,
cfgno , size2 , plural ( size2 ) ) ;
break ;
}
header = ( struct usb_descriptor_header * ) buffer2 ;
if ( ( header - > bLength > size2 ) | | ( header - > bLength < 2 ) ) {
dev_warn ( ddev , " config %d has an invalid descriptor "
" of length %d, skipping remainder of the config \n " ,
cfgno , header - > bLength ) ;
break ;
}
if ( header - > bDescriptorType = = USB_DT_INTERFACE ) {
struct usb_interface_descriptor * d ;
int inum ;
d = ( struct usb_interface_descriptor * ) header ;
if ( d - > bLength < USB_DT_INTERFACE_SIZE ) {
dev_warn ( ddev , " config %d has an invalid "
" interface descriptor of length %d, "
" skipping \n " , cfgno , d - > bLength ) ;
continue ;
}
inum = d - > bInterfaceNumber ;
if ( inum > = nintf_orig )
dev_warn ( ddev , " config %d has an invalid "
" interface number: %d but max is %d \n " ,
cfgno , inum , nintf_orig - 1 ) ;
/* Have we already encountered this interface?
* Count its altsettings */
for ( i = 0 ; i < n ; + + i ) {
if ( inums [ i ] = = inum )
break ;
}
if ( i < n ) {
if ( nalts [ i ] < 255 )
+ + nalts [ i ] ;
} else if ( n < USB_MAXINTERFACES ) {
inums [ n ] = inum ;
nalts [ n ] = 1 ;
+ + n ;
}
} else if ( header - > bDescriptorType = = USB_DT_DEVICE | |
header - > bDescriptorType = = USB_DT_CONFIG )
dev_warn ( ddev , " config %d contains an unexpected "
" descriptor of type 0x%X, skipping \n " ,
cfgno , header - > bDescriptorType ) ;
} /* for ((buffer2 = buffer, size2 = size); ...) */
size = buffer2 - buffer ;
config - > desc . wTotalLength = cpu_to_le16 ( buffer2 - buffer0 ) ;
if ( n ! = nintf )
dev_warn ( ddev , " config %d has %d interface%s, different from "
" the descriptor's value: %d \n " ,
cfgno , n , plural ( n ) , nintf_orig ) ;
else if ( n = = 0 )
dev_warn ( ddev , " config %d has no interfaces? \n " , cfgno ) ;
config - > desc . bNumInterfaces = nintf = n ;
/* Check for missing interface numbers */
for ( i = 0 ; i < nintf ; + + i ) {
for ( j = 0 ; j < nintf ; + + j ) {
if ( inums [ j ] = = i )
break ;
}
if ( j > = nintf )
dev_warn ( ddev , " config %d has no interface number "
" %d \n " , cfgno , i ) ;
}
/* Allocate the usb_interface_caches and altsetting arrays */
for ( i = 0 ; i < nintf ; + + i ) {
j = nalts [ i ] ;
if ( j > USB_MAXALTSETTING ) {
dev_warn ( ddev , " too many alternate settings for "
" config %d interface %d: %d, "
" using maximum allowed: %d \n " ,
cfgno , inums [ i ] , j , USB_MAXALTSETTING ) ;
nalts [ i ] = j = USB_MAXALTSETTING ;
}
len = sizeof ( * intfc ) + sizeof ( struct usb_host_interface ) * j ;
2005-10-24 23:38:24 +04:00
config - > intf_cache [ i ] = intfc = kzalloc ( len , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! intfc )
return - ENOMEM ;
kref_init ( & intfc - > ref ) ;
}
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the first interface descriptor */
config - > extra = buffer ;
i = find_next_descriptor ( buffer , size , USB_DT_INTERFACE ,
USB_DT_INTERFACE , & n ) ;
config - > extralen = i ;
if ( n > 0 )
dev_dbg ( ddev , " skipped %d descriptor%s after %s \n " ,
n , plural ( n ) , " configuration " ) ;
buffer + = i ;
size - = i ;
/* Parse all the interface/altsetting descriptors */
while ( size > 0 ) {
retval = usb_parse_interface ( ddev , cfgno , config ,
buffer , size , inums , nalts ) ;
if ( retval < 0 )
return retval ;
buffer + = retval ;
size - = retval ;
}
/* Check for missing altsettings */
for ( i = 0 ; i < nintf ; + + i ) {
intfc = config - > intf_cache [ i ] ;
for ( j = 0 ; j < intfc - > num_altsetting ; + + j ) {
for ( n = 0 ; n < intfc - > num_altsetting ; + + n ) {
if ( intfc - > altsetting [ n ] . desc .
bAlternateSetting = = j )
break ;
}
if ( n > = intfc - > num_altsetting )
dev_warn ( ddev , " config %d interface %d has no "
" altsetting %d \n " , cfgno , inums [ i ] , j ) ;
}
}
return 0 ;
}
// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally on disconnect/destroy path
void usb_destroy_configuration ( struct usb_device * dev )
{
int c , i ;
if ( ! dev - > config )
return ;
if ( dev - > rawdescriptors ) {
for ( i = 0 ; i < dev - > descriptor . bNumConfigurations ; i + + )
kfree ( dev - > rawdescriptors [ i ] ) ;
kfree ( dev - > rawdescriptors ) ;
dev - > rawdescriptors = NULL ;
}
for ( c = 0 ; c < dev - > descriptor . bNumConfigurations ; c + + ) {
struct usb_host_config * cf = & dev - > config [ c ] ;
kfree ( cf - > string ) ;
for ( i = 0 ; i < cf - > desc . bNumInterfaces ; i + + ) {
if ( cf - > intf_cache [ i ] )
kref_put ( & cf - > intf_cache [ i ] - > ref ,
usb_release_interface_cache ) ;
}
}
kfree ( dev - > config ) ;
dev - > config = NULL ;
}
// hub-only!! ... and only in reset path, or usb_new_device()
// (used by real hubs and virtual root hubs)
int usb_get_configuration ( struct usb_device * dev )
{
struct device * ddev = & dev - > dev ;
int ncfg = dev - > descriptor . bNumConfigurations ;
int result = - ENOMEM ;
unsigned int cfgno , length ;
unsigned char * buffer ;
unsigned char * bigbuffer ;
struct usb_config_descriptor * desc ;
if ( ncfg > USB_MAXCONFIG ) {
dev_warn ( ddev , " too many configurations: %d, "
" using maximum allowed: %d \n " , ncfg , USB_MAXCONFIG ) ;
dev - > descriptor . bNumConfigurations = ncfg = USB_MAXCONFIG ;
}
if ( ncfg < 1 ) {
dev_err ( ddev , " no configurations \n " ) ;
return - EINVAL ;
}
length = ncfg * sizeof ( struct usb_host_config ) ;
2005-10-24 23:38:24 +04:00
dev - > config = kzalloc ( length , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev - > config )
goto err2 ;
length = ncfg * sizeof ( char * ) ;
2005-10-24 23:38:24 +04:00
dev - > rawdescriptors = kzalloc ( length , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev - > rawdescriptors )
goto err2 ;
buffer = kmalloc ( USB_DT_CONFIG_SIZE , GFP_KERNEL ) ;
if ( ! buffer )
goto err2 ;
desc = ( struct usb_config_descriptor * ) buffer ;
for ( cfgno = 0 ; cfgno < ncfg ; cfgno + + ) {
/* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor ( dev , USB_DT_CONFIG , cfgno ,
buffer , USB_DT_CONFIG_SIZE ) ;
if ( result < 0 ) {
dev_err ( ddev , " unable to read config index %d "
" descriptor/%s \n " , cfgno , " start " ) ;
2006-08-26 06:35:28 +04:00
dev_err ( ddev , " chopping to %d config(s) \n " , cfgno ) ;
dev - > descriptor . bNumConfigurations = cfgno ;
break ;
2005-04-17 02:20:36 +04:00
} else if ( result < 4 ) {
dev_err ( ddev , " config index %d descriptor too short "
" (expected %i, got %i) \n " , cfgno ,
USB_DT_CONFIG_SIZE , result ) ;
result = - EINVAL ;
goto err ;
}
length = max ( ( int ) le16_to_cpu ( desc - > wTotalLength ) ,
USB_DT_CONFIG_SIZE ) ;
/* Now that we know the length, get the whole thing */
bigbuffer = kmalloc ( length , GFP_KERNEL ) ;
if ( ! bigbuffer ) {
result = - ENOMEM ;
goto err ;
}
result = usb_get_descriptor ( dev , USB_DT_CONFIG , cfgno ,
bigbuffer , length ) ;
if ( result < 0 ) {
dev_err ( ddev , " unable to read config index %d "
" descriptor/%s \n " , cfgno , " all " ) ;
kfree ( bigbuffer ) ;
goto err ;
}
if ( result < length ) {
dev_warn ( ddev , " config index %d descriptor too short "
" (expected %i, got %i) \n " , cfgno , length , result ) ;
length = result ;
}
dev - > rawdescriptors [ cfgno ] = bigbuffer ;
result = usb_parse_configuration ( & dev - > dev , cfgno ,
& dev - > config [ cfgno ] , bigbuffer , length ) ;
if ( result < 0 ) {
+ + cfgno ;
goto err ;
}
}
result = 0 ;
err :
kfree ( buffer ) ;
dev - > descriptor . bNumConfigurations = cfgno ;
err2 :
if ( result = = - ENOMEM )
dev_err ( ddev , " out of memory \n " ) ;
return result ;
}