2017-11-03 11:18:41 +03:00
// SPDX-License-Identifier: GPL-2.0
2016-10-29 00:16:36 +03:00
/*
* Released under the GPLv2 only .
*/
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>
2010-04-25 01:21:52 +04:00
# include <linux/usb/hcd.h>
2010-03-29 14:03:17 +04:00
# include <linux/usb/quirks.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/device.h>
# include <asm/byteorder.h>
2005-04-19 04:39:24 +04:00
# include "usb.h"
2010-04-25 01:21:52 +04:00
2005-04-17 02:20:36 +04:00
# define USB_MAXALTSETTING 128 /* 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 ;
}
2016-02-12 17:40:13 +03:00
static void usb_parse_ssp_isoc_endpoint_companion ( struct device * ddev ,
int cfgno , int inum , int asnum , struct usb_host_endpoint * ep ,
unsigned char * buffer , int size )
{
struct usb_ssp_isoc_ep_comp_descriptor * desc ;
/*
* The SuperSpeedPlus Isoc endpoint companion descriptor immediately
* follows the SuperSpeed Endpoint Companion descriptor
*/
desc = ( struct usb_ssp_isoc_ep_comp_descriptor * ) buffer ;
if ( desc - > bDescriptorType ! = USB_DT_SSP_ISOC_ENDPOINT_COMP | |
size < USB_DT_SSP_ISOC_EP_COMP_SIZE ) {
dev_warn ( ddev , " Invalid SuperSpeedPlus isoc endpoint companion "
" for config %d interface %d altsetting %d ep %d. \n " ,
cfgno , inum , asnum , ep - > desc . bEndpointAddress ) ;
return ;
}
memcpy ( & ep - > ssp_isoc_ep_comp , desc , USB_DT_SSP_ISOC_EP_COMP_SIZE ) ;
}
2010-04-30 20:44:46 +04:00
static void usb_parse_ss_endpoint_companion ( struct device * ddev , int cfgno ,
2009-04-28 06:58:14 +04:00
int inum , int asnum , struct usb_host_endpoint * ep ,
2010-04-30 20:44:46 +04:00
unsigned char * buffer , int size )
2009-04-28 06:58:14 +04:00
{
2010-04-30 20:44:46 +04:00
struct usb_ss_ep_comp_descriptor * desc ;
2009-04-28 06:58:14 +04:00
int max_tx ;
2010-04-30 20:44:46 +04:00
/* The SuperSpeed endpoint companion descriptor is supposed to
* be the first thing immediately following the endpoint descriptor .
*/
2009-04-30 06:06:20 +04:00
desc = ( struct usb_ss_ep_comp_descriptor * ) buffer ;
2016-02-12 17:40:13 +03:00
2010-04-30 20:44:46 +04:00
if ( desc - > bDescriptorType ! = USB_DT_SS_ENDPOINT_COMP | |
size < USB_DT_SS_EP_COMP_SIZE ) {
2009-04-28 06:58:14 +04:00
dev_warn ( ddev , " No SuperSpeed endpoint companion for config %d "
" interface %d altsetting %d ep %d: "
" using minimum values \n " ,
cfgno , inum , asnum , ep - > desc . bEndpointAddress ) ;
2010-04-30 20:44:46 +04:00
/* Fill in some default values.
* Leave bmAttributes as zero , which will mean no streams for
* bulk , and isoc won ' t support multiple bursts of packets .
* With bursts of only one packet , and a Mult of 1 , the max
* amount of data moved per endpoint service interval is one
* packet .
2009-04-28 06:58:14 +04:00
*/
2010-04-30 20:44:46 +04:00
ep - > ss_ep_comp . bLength = USB_DT_SS_EP_COMP_SIZE ;
ep - > ss_ep_comp . bDescriptorType = USB_DT_SS_ENDPOINT_COMP ;
if ( usb_endpoint_xfer_isoc ( & ep - > desc ) | |
usb_endpoint_xfer_int ( & ep - > desc ) )
ep - > ss_ep_comp . wBytesPerInterval =
ep - > desc . wMaxPacketSize ;
return ;
2009-04-28 06:58:14 +04:00
}
2016-03-29 13:47:09 +03:00
buffer + = desc - > bLength ;
size - = desc - > bLength ;
2010-04-30 20:44:46 +04:00
memcpy ( & ep - > ss_ep_comp , desc , USB_DT_SS_EP_COMP_SIZE ) ;
2009-04-28 06:58:14 +04:00
/* Check the various values */
if ( usb_endpoint_xfer_control ( & ep - > desc ) & & desc - > bMaxBurst ! = 0 ) {
dev_warn ( ddev , " Control endpoint with bMaxBurst = %d in "
" config %d interface %d altsetting %d ep %d: "
" setting to zero \n " , desc - > bMaxBurst ,
cfgno , inum , asnum , ep - > desc . bEndpointAddress ) ;
2010-04-30 20:44:46 +04:00
ep - > ss_ep_comp . bMaxBurst = 0 ;
} else if ( desc - > bMaxBurst > 15 ) {
2009-04-28 06:58:14 +04:00
dev_warn ( ddev , " Endpoint with bMaxBurst = %d in "
" config %d interface %d altsetting %d ep %d: "
" setting to 15 \n " , desc - > bMaxBurst ,
cfgno , inum , asnum , ep - > desc . bEndpointAddress ) ;
2010-04-30 20:44:46 +04:00
ep - > ss_ep_comp . bMaxBurst = 15 ;
2009-04-28 06:58:14 +04:00
}
2010-04-30 20:44:46 +04:00
if ( ( usb_endpoint_xfer_control ( & ep - > desc ) | |
usb_endpoint_xfer_int ( & ep - > desc ) ) & &
desc - > bmAttributes ! = 0 ) {
2009-04-28 06:58:14 +04:00
dev_warn ( ddev , " %s endpoint with bmAttributes = %d in "
" config %d interface %d altsetting %d ep %d: "
" setting to zero \n " ,
usb_endpoint_xfer_control ( & ep - > desc ) ? " Control " : " Bulk " ,
desc - > bmAttributes ,
cfgno , inum , asnum , ep - > desc . bEndpointAddress ) ;
2010-04-30 20:44:46 +04:00
ep - > ss_ep_comp . bmAttributes = 0 ;
} else if ( usb_endpoint_xfer_bulk ( & ep - > desc ) & &
desc - > bmAttributes > 16 ) {
2009-04-28 06:58:14 +04:00
dev_warn ( ddev , " Bulk endpoint with more than 65536 streams in "
" config %d interface %d altsetting %d ep %d: "
" setting to max \n " ,
cfgno , inum , asnum , ep - > desc . bEndpointAddress ) ;
2010-04-30 20:44:46 +04:00
ep - > ss_ep_comp . bmAttributes = 16 ;
} else if ( usb_endpoint_xfer_isoc ( & ep - > desc ) & &
2016-02-12 17:40:13 +03:00
! USB_SS_SSP_ISOC_COMP ( desc - > bmAttributes ) & &
2015-09-21 17:46:09 +03:00
USB_SS_MULT ( desc - > bmAttributes ) > 3 ) {
2009-04-28 06:58:14 +04:00
dev_warn ( ddev , " Isoc endpoint has Mult of %d in "
" config %d interface %d altsetting %d ep %d: "
2015-11-18 05:01:21 +03:00
" setting to 3 \n " ,
USB_SS_MULT ( desc - > bmAttributes ) ,
2009-04-28 06:58:14 +04:00
cfgno , inum , asnum , ep - > desc . bEndpointAddress ) ;
2010-04-30 20:44:46 +04:00
ep - > ss_ep_comp . bmAttributes = 2 ;
2009-04-28 06:58:14 +04:00
}
2010-04-30 20:44:46 +04:00
if ( usb_endpoint_xfer_isoc ( & ep - > desc ) )
2015-09-21 17:46:09 +03:00
max_tx = ( desc - > bMaxBurst + 1 ) *
( USB_SS_MULT ( desc - > bmAttributes ) ) *
2011-08-23 14:12:03 +04:00
usb_endpoint_maxp ( & ep - > desc ) ;
2010-04-30 20:44:46 +04:00
else if ( usb_endpoint_xfer_int ( & ep - > desc ) )
2011-08-23 14:12:03 +04:00
max_tx = usb_endpoint_maxp ( & ep - > desc ) *
2011-07-29 13:05:45 +04:00
( desc - > bMaxBurst + 1 ) ;
2010-04-30 20:44:46 +04:00
else
max_tx = 999999 ;
2011-04-11 22:19:12 +04:00
if ( le16_to_cpu ( desc - > wBytesPerInterval ) > max_tx ) {
2009-04-28 06:58:14 +04:00
dev_warn ( ddev , " %s endpoint with wBytesPerInterval of %d in "
" config %d interface %d altsetting %d ep %d: "
" setting to %d \n " ,
usb_endpoint_xfer_isoc ( & ep - > desc ) ? " Isoc " : " Int " ,
2011-07-29 13:05:45 +04:00
le16_to_cpu ( desc - > wBytesPerInterval ) ,
2009-04-28 06:58:14 +04:00
cfgno , inum , asnum , ep - > desc . bEndpointAddress ,
max_tx ) ;
2011-07-29 13:05:45 +04:00
ep - > ss_ep_comp . wBytesPerInterval = cpu_to_le16 ( max_tx ) ;
2009-04-28 06:58:14 +04:00
}
2016-03-29 13:47:09 +03:00
/* Parse a possible SuperSpeedPlus isoc ep companion descriptor */
if ( usb_endpoint_xfer_isoc ( & ep - > desc ) & &
USB_SS_SSP_ISOC_COMP ( desc - > bmAttributes ) )
usb_parse_ssp_isoc_endpoint_companion ( ddev , cfgno , inum , asnum ,
ep , buffer , size ) ;
2009-04-28 06:58:14 +04:00
}
2016-08-01 22:25:56 +03:00
static const unsigned short low_speed_maxpacket_maxes [ 4 ] = {
[ USB_ENDPOINT_XFER_CONTROL ] = 8 ,
[ USB_ENDPOINT_XFER_ISOC ] = 0 ,
[ USB_ENDPOINT_XFER_BULK ] = 0 ,
[ USB_ENDPOINT_XFER_INT ] = 8 ,
} ;
static const unsigned short full_speed_maxpacket_maxes [ 4 ] = {
[ USB_ENDPOINT_XFER_CONTROL ] = 64 ,
[ USB_ENDPOINT_XFER_ISOC ] = 1023 ,
[ USB_ENDPOINT_XFER_BULK ] = 64 ,
[ USB_ENDPOINT_XFER_INT ] = 64 ,
} ;
static const unsigned short high_speed_maxpacket_maxes [ 4 ] = {
[ USB_ENDPOINT_XFER_CONTROL ] = 64 ,
[ USB_ENDPOINT_XFER_ISOC ] = 1024 ,
2018-05-03 18:04:48 +03:00
/* Bulk should be 512, but some devices use 1024: we will warn below */
[ USB_ENDPOINT_XFER_BULK ] = 1024 ,
2016-08-22 23:58:53 +03:00
[ USB_ENDPOINT_XFER_INT ] = 1024 ,
2016-08-01 22:25:56 +03:00
} ;
static const unsigned short super_speed_maxpacket_maxes [ 4 ] = {
[ USB_ENDPOINT_XFER_CONTROL ] = 512 ,
[ USB_ENDPOINT_XFER_ISOC ] = 1024 ,
[ USB_ENDPOINT_XFER_BULK ] = 1024 ,
[ USB_ENDPOINT_XFER_INT ] = 1024 ,
} ;
2019-12-19 19:10:16 +03:00
static bool endpoint_is_duplicate ( struct usb_endpoint_descriptor * e1 ,
struct usb_endpoint_descriptor * e2 )
{
if ( e1 - > bEndpointAddress = = e2 - > bEndpointAddress )
return true ;
if ( usb_endpoint_xfer_control ( e1 ) | | usb_endpoint_xfer_control ( e2 ) ) {
if ( usb_endpoint_num ( e1 ) = = usb_endpoint_num ( e2 ) )
return true ;
}
return false ;
}
/*
* Check for duplicate endpoint addresses in other interfaces and in the
* altsetting currently being parsed .
*/
static bool config_endpoint_is_duplicate ( struct usb_host_config * config ,
int inum , int asnum , struct usb_endpoint_descriptor * d )
{
struct usb_endpoint_descriptor * epd ;
struct usb_interface_cache * intfc ;
struct usb_host_interface * alt ;
int i , j , k ;
for ( i = 0 ; i < config - > desc . bNumInterfaces ; + + i ) {
intfc = config - > intf_cache [ i ] ;
for ( j = 0 ; j < intfc - > num_altsetting ; + + j ) {
alt = & intfc - > altsetting [ j ] ;
if ( alt - > desc . bInterfaceNumber = = inum & &
alt - > desc . bAlternateSetting ! = asnum )
continue ;
for ( k = 0 ; k < alt - > desc . bNumEndpoints ; + + k ) {
epd = & alt - > endpoint [ k ] . desc ;
if ( endpoint_is_duplicate ( epd , d ) )
return true ;
}
}
}
return false ;
}
static int usb_parse_endpoint ( struct device * ddev , int cfgno ,
struct usb_host_config * config , int inum , int asnum ,
struct usb_host_interface * ifp , int num_ep ,
unsigned char * buffer , int size )
2005-04-17 02:20:36 +04:00
{
2020-02-03 18:38:28 +03:00
struct usb_device * udev = to_usb_device ( ddev ) ;
2005-04-17 02:20:36 +04:00
unsigned char * buffer0 = buffer ;
struct usb_endpoint_descriptor * d ;
struct usb_host_endpoint * endpoint ;
2009-04-28 06:58:14 +04:00
int n , i , j , retval ;
2016-08-01 22:25:56 +03:00
unsigned int maxp ;
const unsigned short * maxpacket_maxes ;
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 ;
2016-12-19 20:03:41 +03:00
/* Check for duplicate endpoint addresses */
2019-12-19 19:10:16 +03:00
if ( config_endpoint_is_duplicate ( config , inum , asnum , d ) ) {
dev_warn ( ddev , " config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping \n " ,
cfgno , inum , asnum , d - > bEndpointAddress ) ;
goto skip_to_next_endpoint_or_interface_descriptor ;
2016-12-19 20:03:41 +03:00
}
2020-06-18 12:42:53 +03:00
/* Ignore some endpoints */
if ( udev - > quirks & USB_QUIRK_ENDPOINT_IGNORE ) {
if ( usb_endpoint_is_ignored ( udev , ifp , d ) ) {
dev_warn ( ddev , " config %d interface %d altsetting %d has an ignored endpoint with address 0x%X, skipping \n " ,
2020-02-03 18:38:28 +03:00
cfgno , inum , asnum ,
d - > bEndpointAddress ) ;
goto skip_to_next_endpoint_or_interface_descriptor ;
}
}
2005-04-17 02:20:36 +04:00
endpoint = & ifp - > endpoint [ ifp - > desc . bNumEndpoints ] ;
+ + ifp - > desc . bNumEndpoints ;
memcpy ( & endpoint - > desc , d , n ) ;
INIT_LIST_HEAD ( & endpoint - > urb_list ) ;
2016-09-16 17:24:26 +03:00
/*
* Fix up bInterval values outside the legal range .
* Use 10 or 8 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 ;
2020-02-03 18:38:30 +03:00
switch ( udev - > speed ) {
2015-12-10 10:59:25 +03:00
case USB_SPEED_SUPER_PLUS :
2009-04-28 06:54:10 +04:00
case USB_SPEED_SUPER :
2007-06-08 23:23:27 +04:00
case USB_SPEED_HIGH :
2016-09-16 17:24:26 +03:00
/*
* Many device manufacturers are using full - speed
2007-06-12 23:47:17 +04:00
* bInterval values in high - speed interrupt endpoint
2016-09-16 17:24:26 +03:00
* descriptors . Try to fix those and fall back to an
* 8 - ms default value otherwise .
*/
2007-06-12 23:47:17 +04:00
n = fls ( d - > bInterval * 8 ) ;
if ( n = = 0 )
2016-09-16 17:24:26 +03:00
n = 7 ; /* 8 ms = 2^(7-1) uframes */
2007-06-08 23:23:27 +04:00
j = 16 ;
2014-07-27 21:28:04 +04:00
/*
* Adjust bInterval for quirked devices .
2017-03-13 22:50:08 +03:00
*/
/*
* This quirk fixes bIntervals reported in ms .
*/
2020-02-03 18:38:30 +03:00
if ( udev - > quirks & USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL ) {
2017-03-13 22:50:08 +03:00
n = clamp ( fls ( d - > bInterval ) + 3 , i , j ) ;
i = j = n ;
}
/*
2014-07-27 21:28:04 +04:00
* This quirk fixes bIntervals reported in
* linear microframes .
*/
2020-02-03 18:38:30 +03:00
if ( udev - > quirks & USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL ) {
2014-07-27 21:28:04 +04:00
n = clamp ( fls ( d - > bInterval ) , i , j ) ;
i = j = n ;
}
2007-06-08 23:23:27 +04:00
break ;
default : /* USB_SPEED_FULL or _LOW */
2016-09-16 17:24:26 +03:00
/*
* For low - speed , 10 ms is the official minimum .
2007-06-08 23:23:27 +04:00
* But some " overclocked " devices might want faster
2016-09-16 17:24:26 +03:00
* polling so we ' ll allow it .
*/
n = 10 ;
2007-06-08 23:23:27 +04:00
break ;
}
} else if ( usb_endpoint_xfer_isoc ( d ) ) {
i = 1 ;
j = 16 ;
2020-02-03 18:38:30 +03:00
switch ( udev - > speed ) {
2007-06-08 23:23:27 +04:00
case USB_SPEED_HIGH :
2016-09-16 17:24:26 +03:00
n = 7 ; /* 8 ms = 2^(7-1) uframes */
2007-06-08 23:23:27 +04:00
break ;
default : /* USB_SPEED_FULL */
2016-09-16 17:24:26 +03:00
n = 4 ; /* 8 ms = 2^(4-1) frames */
2007-06-08 23:23:27 +04:00
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 .
*/
2020-02-03 18:38:30 +03:00
if ( udev - > speed = = USB_SPEED_LOW & & usb_endpoint_xfer_bulk ( d ) ) {
2007-06-08 23:25:02 +04:00
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 ;
2011-08-23 14:12:03 +04:00
if ( usb_endpoint_maxp ( & endpoint - > desc ) > 8 )
2007-06-08 23:25:02 +04:00
endpoint - > desc . wMaxPacketSize = cpu_to_le16 ( 8 ) ;
}
2020-01-06 18:43:42 +03:00
/*
* Validate the wMaxPacketSize field .
* Some devices have isochronous endpoints in altsetting 0 ;
* the USB - 2 spec requires such endpoints to have wMaxPacketSize = 0
* ( see the end of section 5.6 .3 ) , so don ' t warn about them .
*/
2021-12-10 11:52:18 +03:00
maxp = le16_to_cpu ( endpoint - > desc . wMaxPacketSize ) ;
2020-01-06 18:43:42 +03:00
if ( maxp = = 0 & & ! ( usb_endpoint_xfer_isoc ( d ) & & asnum = = 0 ) ) {
dev_warn ( ddev , " config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0 \n " ,
2019-10-28 17:52:35 +03:00
cfgno , inum , asnum , d - > bEndpointAddress ) ;
}
2016-08-01 22:25:56 +03:00
/* Find the highest legal maxpacket size for this endpoint */
i = 0 ; /* additional transactions per microframe */
2020-02-03 18:38:30 +03:00
switch ( udev - > speed ) {
2016-08-01 22:25:56 +03:00
case USB_SPEED_LOW :
maxpacket_maxes = low_speed_maxpacket_maxes ;
break ;
case USB_SPEED_FULL :
maxpacket_maxes = full_speed_maxpacket_maxes ;
break ;
case USB_SPEED_HIGH :
2021-12-10 11:52:19 +03:00
/* Multiple-transactions bits are allowed only for HS periodic endpoints */
2016-08-01 22:25:56 +03:00
if ( usb_endpoint_xfer_int ( d ) | | usb_endpoint_xfer_isoc ( d ) ) {
2021-12-10 11:52:19 +03:00
i = maxp & USB_EP_MAXP_MULT_MASK ;
2016-08-01 22:25:56 +03:00
maxp & = ~ i ;
}
2020-07-07 22:56:07 +03:00
fallthrough ;
2016-08-01 22:25:56 +03:00
default :
maxpacket_maxes = high_speed_maxpacket_maxes ;
break ;
case USB_SPEED_SUPER :
case USB_SPEED_SUPER_PLUS :
maxpacket_maxes = super_speed_maxpacket_maxes ;
break ;
}
j = maxpacket_maxes [ usb_endpoint_type ( & endpoint - > desc ) ] ;
if ( maxp > j ) {
dev_warn ( ddev , " config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d \n " ,
cfgno , inum , asnum , d - > bEndpointAddress , maxp , j ) ;
maxp = j ;
endpoint - > desc . wMaxPacketSize = cpu_to_le16 ( i | maxp ) ;
}
2008-02-09 02:08:44 +03:00
/*
* Some buggy high speed devices have bulk endpoints using
* maxpacket sizes other than 512. High speed HCDs may not
* be able to handle that particular bug , so let ' s warn . . .
*/
2020-02-03 18:38:30 +03:00
if ( udev - > speed = = USB_SPEED_HIGH & & usb_endpoint_xfer_bulk ( d ) ) {
2008-02-09 02:08:44 +03:00
if ( maxp ! = 512 )
dev_warn ( ddev , " config %d interface %d altsetting %d "
" bulk endpoint 0x%X has invalid maxpacket %d \n " ,
cfgno , inum , asnum , d - > bEndpointAddress ,
maxp ) ;
}
2009-04-28 06:58:14 +04:00
2010-04-30 20:44:46 +04:00
/* Parse a possible SuperSpeed endpoint companion descriptor */
2020-02-03 18:38:30 +03:00
if ( udev - > speed > = USB_SPEED_SUPER )
2010-04-30 20:44:46 +04:00
usb_parse_ss_endpoint_companion ( ddev , cfgno ,
inum , asnum , endpoint , buffer , size ) ;
2009-07-27 23:04:52 +04:00
2010-04-30 20:44:46 +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 ;
retval = buffer - buffer0 + i ;
2005-04-17 02:20:36 +04:00
if ( n > 0 )
dev_dbg ( ddev , " skipped %d descriptor%s after %s \n " ,
n , plural ( n ) , " endpoint " ) ;
2009-04-28 06:58:14 +04:00
return retval ;
2005-04-17 02:20:36 +04:00
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 ;
2008-01-31 02:21:33 +03:00
alt - > desc . bNumEndpoints = 0 ; /* Use as a counter */
2005-04-17 02:20:36 +04:00
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 ;
}
2008-01-31 02:21:33 +03:00
if ( num_ep > 0 ) {
/* Can't allocate 0 bytes */
2007-05-16 01:40:37 +04:00
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 ;
2019-12-19 19:10:16 +03:00
retval = usb_parse_endpoint ( ddev , cfgno , config , inum , asnum ,
alt , num_ep , buffer , size ) ;
2005-04-17 02:20:36 +04:00
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 ;
}
2010-03-29 14:03:17 +04:00
static int usb_parse_configuration ( struct usb_device * dev , int cfgidx ,
2005-04-17 02:20:36 +04:00
struct usb_host_config * config , unsigned char * buffer , int size )
{
2010-03-29 14:03:17 +04:00
struct device * ddev = & dev - > dev ;
2005-04-17 02:20:36 +04:00
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 ;
2019-02-18 22:06:41 +03:00
int retval ;
2005-04-17 02:20:36 +04:00
u8 inums [ USB_MAXINTERFACES ] , nalts [ USB_MAXINTERFACES ] ;
2007-06-16 07:14:35 +04:00
unsigned iad_num = 0 ;
2005-04-17 02:20:36 +04:00
memcpy ( & config - > desc , buffer , USB_DT_CONFIG_SIZE ) ;
2017-12-12 22:25:13 +03:00
nintf = nintf_orig = config - > desc . bNumInterfaces ;
config - > desc . bNumInterfaces = 0 ; // Adjusted later
2005-04-17 02:20:36 +04:00
if ( config - > desc . bDescriptorType ! = USB_DT_CONFIG | |
2013-08-03 18:37:48 +04:00
config - > desc . bLength < USB_DT_CONFIG_SIZE | |
config - > desc . bLength > size ) {
2005-04-17 02:20:36 +04:00
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 ;
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 ;
2010-03-29 14:03:17 +04:00
if ( ( dev - > quirks & USB_QUIRK_HONOR_BNUMINTERFACES ) & &
n > = nintf_orig ) {
dev_warn ( ddev , " config %d has more interface "
" descriptors, than it declares in "
" bNumInterfaces, ignoring interface "
" number: %d \n " , cfgno , inum ) ;
continue ;
}
2005-04-17 02:20:36 +04:00
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 ;
}
2007-06-16 07:14:35 +04:00
} else if ( header - > bDescriptorType = =
USB_DT_INTERFACE_ASSOCIATION ) {
2017-09-19 16:07:17 +03:00
struct usb_interface_assoc_descriptor * d ;
d = ( struct usb_interface_assoc_descriptor * ) header ;
if ( d - > bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE ) {
dev_warn ( ddev ,
" config %d has an invalid interface association descriptor of length %d, skipping \n " ,
cfgno , d - > bLength ) ;
continue ;
}
2007-06-16 07:14:35 +04:00
if ( iad_num = = USB_MAXIADS ) {
dev_warn ( ddev , " found more Interface "
" Association Descriptors "
" than allocated for in "
" configuration %d \n " , cfgno ) ;
} else {
2017-09-19 16:07:17 +03:00
config - > intf_assoc [ iad_num ] = d ;
2007-06-16 07:14:35 +04:00
iad_num + + ;
}
2005-04-17 02:20:36 +04:00
} 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 ;
}
2019-02-18 22:06:41 +03:00
intfc = kzalloc ( struct_size ( intfc , altsetting , j ) , GFP_KERNEL ) ;
config - > intf_cache [ i ] = intfc ;
2005-04-17 02:20:36 +04:00
if ( ! intfc )
return - ENOMEM ;
kref_init ( & intfc - > ref ) ;
}
2009-04-28 06:58:14 +04:00
/* FIXME: parse the BOS descriptor */
2005-04-17 02:20:36 +04:00
/* 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 ;
}
2008-01-31 02:21:33 +03:00
/* hub-only!! ... and only exported for reset/reinit path.
* otherwise used internally on disconnect / destroy path
*/
2005-04-17 02:20:36 +04:00
void usb_destroy_configuration ( struct usb_device * dev )
{
int c , i ;
if ( ! dev - > config )
return ;
if ( dev - > rawdescriptors ) {
2017-12-13 13:59:39 +03:00
for ( i = 0 ; i < dev - > descriptor . bNumConfigurations ; i + + )
2005-04-17 02:20:36 +04:00
kfree ( dev - > rawdescriptors [ i ] ) ;
kfree ( dev - > rawdescriptors ) ;
dev - > rawdescriptors = NULL ;
}
2017-12-13 13:59:39 +03:00
for ( c = 0 ; c < dev - > descriptor . bNumConfigurations ; c + + ) {
2005-04-17 02:20:36 +04:00
struct usb_host_config * cf = & dev - > config [ c ] ;
kfree ( cf - > string ) ;
2017-12-13 13:59:39 +03:00
for ( i = 0 ; i < cf - > desc . bNumInterfaces ; i + + ) {
2005-04-17 02:20:36 +04:00
if ( cf - > intf_cache [ i ] )
2008-01-31 02:21:33 +03:00
kref_put ( & cf - > intf_cache [ i ] - > ref ,
2005-04-17 02:20:36 +04:00
usb_release_interface_cache ) ;
}
}
kfree ( dev - > config ) ;
dev - > config = NULL ;
}
2007-08-01 07:34:02 +04:00
/*
* Get the USB config descriptors , cache and parse ' em
*
* hub - only ! ! . . . and only in reset path , or usb_new_device ( )
* ( used by real hubs and virtual root hubs )
*/
2005-04-17 02:20:36 +04:00
int usb_get_configuration ( struct usb_device * dev )
{
struct device * ddev = & dev - > dev ;
int ncfg = dev - > descriptor . bNumConfigurations ;
unsigned int cfgno , length ;
unsigned char * bigbuffer ;
2008-01-31 02:21:33 +03:00
struct usb_config_descriptor * desc ;
2019-10-08 12:02:40 +03:00
int result ;
2005-04-17 02:20:36 +04:00
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 )
2019-10-08 12:02:40 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
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 )
2019-10-08 12:02:40 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2010-04-17 19:12:58 +04:00
desc = kmalloc ( USB_DT_CONFIG_SIZE , GFP_KERNEL ) ;
if ( ! desc )
2019-10-08 12:02:40 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2019-01-30 17:48:28 +03:00
for ( cfgno = 0 ; cfgno < ncfg ; cfgno + + ) {
2005-04-17 02:20:36 +04:00
/* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor ( dev , USB_DT_CONFIG , cfgno ,
2010-04-17 19:12:58 +04:00
desc , USB_DT_CONFIG_SIZE ) ;
2005-04-17 02:20:36 +04:00
if ( result < 0 ) {
dev_err ( ddev , " unable to read config index %d "
2007-08-01 07:34:02 +04:00
" descriptor/%s: %d \n " , cfgno , " start " , result ) ;
2012-09-05 09:44:37 +04:00
if ( result ! = - EPIPE )
goto err ;
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 ;
}
2014-03-04 23:27:38 +04:00
if ( dev - > quirks & USB_QUIRK_DELAY_INIT )
2017-09-05 11:40:56 +03:00
msleep ( 200 ) ;
2014-03-04 23:27:38 +04:00
2005-04-17 02:20:36 +04:00
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 ;
2010-03-29 14:03:17 +04:00
result = usb_parse_configuration ( dev , cfgno ,
2005-04-17 02:20:36 +04:00
& dev - > config [ cfgno ] , bigbuffer , length ) ;
if ( result < 0 ) {
+ + cfgno ;
goto err ;
}
}
err :
2010-04-17 19:12:58 +04:00
kfree ( desc ) ;
2005-04-17 02:20:36 +04:00
dev - > descriptor . bNumConfigurations = cfgno ;
2019-10-08 12:02:40 +03:00
2005-04-17 02:20:36 +04:00
return result ;
}
2011-09-24 01:19:47 +04:00
void usb_release_bos_descriptor ( struct usb_device * dev )
{
if ( dev - > bos ) {
kfree ( dev - > bos - > desc ) ;
kfree ( dev - > bos ) ;
dev - > bos = NULL ;
}
}
2017-11-09 19:25:50 +03:00
static const __u8 bos_desc_len [ 256 ] = {
[ USB_CAP_TYPE_WIRELESS_USB ] = USB_DT_USB_WIRELESS_CAP_SIZE ,
[ USB_CAP_TYPE_EXT ] = USB_DT_USB_EXT_CAP_SIZE ,
[ USB_SS_CAP_TYPE ] = USB_DT_USB_SS_CAP_SIZE ,
[ USB_SSP_CAP_TYPE ] = USB_DT_USB_SSP_CAP_SIZE ( 1 ) ,
[ CONTAINER_ID_TYPE ] = USB_DT_USB_SS_CONTN_ID_SIZE ,
[ USB_PTM_CAP_TYPE ] = USB_DT_USB_PTM_ID_SIZE ,
} ;
2011-09-24 01:19:47 +04:00
/* Get BOS descriptor set */
int usb_get_bos_descriptor ( struct usb_device * dev )
{
struct device * ddev = & dev - > dev ;
struct usb_bos_descriptor * bos ;
struct usb_dev_cap_header * cap ;
2017-11-09 19:25:50 +03:00
struct usb_ssp_cap_descriptor * ssp_cap ;
2019-09-04 18:56:27 +03:00
unsigned char * buffer , * buffer0 ;
2017-11-09 19:25:50 +03:00
int length , total_len , num , i , ssac ;
__u8 cap_type ;
2011-09-24 01:19:47 +04:00
int ret ;
2021-10-01 18:13:50 +03:00
bos = kzalloc ( sizeof ( * bos ) , GFP_KERNEL ) ;
2011-09-24 01:19:47 +04:00
if ( ! bos )
return - ENOMEM ;
/* Get BOS descriptor */
ret = usb_get_descriptor ( dev , USB_DT_BOS , 0 , bos , USB_DT_BOS_SIZE ) ;
2019-05-13 20:14:29 +03:00
if ( ret < USB_DT_BOS_SIZE | | bos - > bLength < USB_DT_BOS_SIZE ) {
dev_err ( ddev , " unable to get BOS descriptor or descriptor too short \n " ) ;
2011-09-24 01:19:47 +04:00
if ( ret > = 0 )
ret = - ENOMSG ;
kfree ( bos ) ;
return ret ;
}
length = bos - > bLength ;
total_len = le16_to_cpu ( bos - > wTotalLength ) ;
num = bos - > bNumDeviceCaps ;
kfree ( bos ) ;
if ( total_len < length )
return - EINVAL ;
2021-10-01 18:13:50 +03:00
dev - > bos = kzalloc ( sizeof ( * dev - > bos ) , GFP_KERNEL ) ;
2011-09-24 01:19:47 +04:00
if ( ! dev - > bos )
return - ENOMEM ;
/* Now let's get the whole BOS descriptor set */
buffer = kzalloc ( total_len , GFP_KERNEL ) ;
if ( ! buffer ) {
ret = - ENOMEM ;
goto err ;
}
dev - > bos - > desc = ( struct usb_bos_descriptor * ) buffer ;
ret = usb_get_descriptor ( dev , USB_DT_BOS , 0 , buffer , total_len ) ;
if ( ret < total_len ) {
dev_err ( ddev , " unable to get BOS descriptor set \n " ) ;
if ( ret > = 0 )
ret = - ENOMSG ;
goto err ;
}
2019-09-04 18:56:27 +03:00
buffer0 = buffer ;
2011-09-24 01:19:47 +04:00
total_len - = length ;
2019-09-04 18:56:27 +03:00
buffer + = length ;
2011-09-24 01:19:47 +04:00
for ( i = 0 ; i < num ; i + + ) {
cap = ( struct usb_dev_cap_header * ) buffer ;
2017-10-18 19:49:38 +03:00
if ( total_len < sizeof ( * cap ) | | total_len < cap - > bLength ) {
dev - > bos - > desc - > bNumDeviceCaps = i ;
2011-09-24 01:19:47 +04:00
break ;
2017-10-18 19:49:38 +03:00
}
2017-11-09 19:25:50 +03:00
cap_type = cap - > bDevCapabilityType ;
2017-10-18 19:49:38 +03:00
length = cap - > bLength ;
2017-11-09 19:25:50 +03:00
if ( bos_desc_len [ cap_type ] & & length < bos_desc_len [ cap_type ] ) {
dev - > bos - > desc - > bNumDeviceCaps = i ;
break ;
}
2011-09-24 01:19:47 +04:00
if ( cap - > bDescriptorType ! = USB_DT_DEVICE_CAPABILITY ) {
dev_warn ( ddev , " descriptor type invalid, skip \n " ) ;
continue ;
}
2017-11-09 19:25:50 +03:00
switch ( cap_type ) {
2011-09-24 01:19:47 +04:00
case USB_CAP_TYPE_WIRELESS_USB :
/* Wireless USB cap descriptor is handled by wusb */
break ;
case USB_CAP_TYPE_EXT :
dev - > bos - > ext_cap =
( struct usb_ext_cap_descriptor * ) buffer ;
break ;
case USB_SS_CAP_TYPE :
dev - > bos - > ss_cap =
( struct usb_ss_cap_descriptor * ) buffer ;
break ;
2015-10-01 18:40:33 +03:00
case USB_SSP_CAP_TYPE :
2017-11-09 19:25:50 +03:00
ssp_cap = ( struct usb_ssp_cap_descriptor * ) buffer ;
ssac = ( le32_to_cpu ( ssp_cap - > bmAttributes ) &
2017-12-19 12:14:42 +03:00
USB_SSP_SUBLINK_SPEED_ATTRIBS ) ;
2017-11-09 19:25:50 +03:00
if ( length > = USB_DT_USB_SSP_CAP_SIZE ( ssac ) )
dev - > bos - > ssp_cap = ssp_cap ;
2015-10-01 18:40:33 +03:00
break ;
2011-09-24 01:19:47 +04:00
case CONTAINER_ID_TYPE :
dev - > bos - > ss_id =
( struct usb_ss_container_id_descriptor * ) buffer ;
break ;
2016-02-12 17:40:14 +03:00
case USB_PTM_CAP_TYPE :
dev - > bos - > ptm_cap =
( struct usb_ptm_cap_descriptor * ) buffer ;
2020-11-11 04:47:14 +03:00
break ;
2011-09-24 01:19:47 +04:00
default :
break ;
}
2019-09-04 18:56:27 +03:00
total_len - = length ;
buffer + = length ;
2011-09-24 01:19:47 +04:00
}
2019-09-04 18:56:27 +03:00
dev - > bos - > desc - > wTotalLength = cpu_to_le16 ( buffer - buffer0 ) ;
2011-09-24 01:19:47 +04:00
return 0 ;
err :
usb_release_bos_descriptor ( dev ) ;
return ret ;
}