2019-08-26 12:19:27 +01:00
// SPDX-License-Identifier: GPL-2.0
2020-07-02 15:45:58 +01:00
/*
2019-08-26 12:19:27 +01:00
* Common USB debugging functions
*
2020-07-19 18:09:10 +02:00
* Copyright ( C ) 2010 - 2011 Texas Instruments Incorporated - https : //www.ti.com
2019-08-26 12:19:27 +01:00
*
* Authors : Felipe Balbi < balbi @ ti . com > ,
* Sebastian Andrzej Siewior < bigeasy @ linutronix . de >
*/
2022-01-05 16:20:27 +01:00
# include <linux/kernel.h>
2019-08-26 12:19:27 +01:00
# include <linux/usb/ch9.h>
static void usb_decode_get_status ( __u8 bRequestType , __u16 wIndex ,
__u16 wLength , char * str , size_t size )
{
switch ( bRequestType & USB_RECIP_MASK ) {
case USB_RECIP_DEVICE :
snprintf ( str , size , " Get Device Status(Length = %d) " , wLength ) ;
break ;
case USB_RECIP_INTERFACE :
snprintf ( str , size ,
" Get Interface Status(Intf = %d, Length = %d) " ,
wIndex , wLength ) ;
break ;
case USB_RECIP_ENDPOINT :
snprintf ( str , size , " Get Endpoint Status(ep%d%s) " ,
wIndex & ~ USB_DIR_IN ,
wIndex & USB_DIR_IN ? " in " : " out " ) ;
break ;
}
}
2019-08-26 12:19:28 +01:00
static const char * usb_decode_device_feature ( u16 wValue )
{
switch ( wValue ) {
case USB_DEVICE_SELF_POWERED :
return " Self Powered " ;
case USB_DEVICE_REMOTE_WAKEUP :
return " Remote Wakeup " ;
case USB_DEVICE_TEST_MODE :
return " Test Mode " ;
case USB_DEVICE_U1_ENABLE :
return " U1 Enable " ;
case USB_DEVICE_U2_ENABLE :
return " U2 Enable " ;
case USB_DEVICE_LTM_ENABLE :
return " LTM Enable " ;
default :
return " UNKNOWN " ;
}
}
static const char * usb_decode_test_mode ( u16 wIndex )
{
switch ( wIndex ) {
2020-06-18 16:42:06 +02:00
case USB_TEST_J :
2019-08-26 12:19:28 +01:00
return " : TEST_J " ;
2020-06-18 16:42:06 +02:00
case USB_TEST_K :
2019-08-26 12:19:28 +01:00
return " : TEST_K " ;
2020-06-18 16:42:06 +02:00
case USB_TEST_SE0_NAK :
2019-08-26 12:19:28 +01:00
return " : TEST_SE0_NAK " ;
2020-06-18 16:42:06 +02:00
case USB_TEST_PACKET :
2019-08-26 12:19:28 +01:00
return " : TEST_PACKET " ;
2020-06-18 16:42:06 +02:00
case USB_TEST_FORCE_ENABLE :
2019-08-26 12:19:28 +01:00
return " : TEST_FORCE_EN " ;
default :
return " : UNKNOWN " ;
}
}
static void usb_decode_set_clear_feature ( __u8 bRequestType ,
__u8 bRequest , __u16 wValue ,
__u16 wIndex , char * str , size_t size )
2019-08-26 12:19:27 +01:00
{
switch ( bRequestType & USB_RECIP_MASK ) {
case USB_RECIP_DEVICE :
snprintf ( str , size , " %s Device Feature(%s%s) " ,
bRequest = = USB_REQ_CLEAR_FEATURE ? " Clear " : " Set " ,
2019-08-26 12:19:28 +01:00
usb_decode_device_feature ( wValue ) ,
2019-08-26 12:19:27 +01:00
wValue = = USB_DEVICE_TEST_MODE ?
2019-08-26 12:19:28 +01:00
usb_decode_test_mode ( wIndex ) : " " ) ;
2019-08-26 12:19:27 +01:00
break ;
case USB_RECIP_INTERFACE :
snprintf ( str , size , " %s Interface Feature(%s) " ,
bRequest = = USB_REQ_CLEAR_FEATURE ? " Clear " : " Set " ,
wValue = = USB_INTRF_FUNC_SUSPEND ?
" Function Suspend " : " UNKNOWN " ) ;
break ;
case USB_RECIP_ENDPOINT :
snprintf ( str , size , " %s Endpoint Feature(%s ep%d%s) " ,
bRequest = = USB_REQ_CLEAR_FEATURE ? " Clear " : " Set " ,
wValue = = USB_ENDPOINT_HALT ? " Halt " : " UNKNOWN " ,
wIndex & ~ USB_DIR_IN ,
wIndex & USB_DIR_IN ? " in " : " out " ) ;
break ;
}
}
static void usb_decode_set_address ( __u16 wValue , char * str , size_t size )
{
snprintf ( str , size , " Set Address(Addr = %02x) " , wValue ) ;
}
static void usb_decode_get_set_descriptor ( __u8 bRequestType , __u8 bRequest ,
__u16 wValue , __u16 wIndex ,
__u16 wLength , char * str , size_t size )
{
2019-08-26 12:19:29 +01:00
char * s ;
switch ( wValue > > 8 ) {
case USB_DT_DEVICE :
s = " Device " ;
break ;
case USB_DT_CONFIG :
s = " Configuration " ;
break ;
case USB_DT_STRING :
s = " String " ;
break ;
case USB_DT_INTERFACE :
s = " Interface " ;
break ;
case USB_DT_ENDPOINT :
s = " Endpoint " ;
break ;
case USB_DT_DEVICE_QUALIFIER :
s = " Device Qualifier " ;
break ;
case USB_DT_OTHER_SPEED_CONFIG :
s = " Other Speed Config " ;
break ;
case USB_DT_INTERFACE_POWER :
s = " Interface Power " ;
break ;
case USB_DT_OTG :
s = " OTG " ;
break ;
case USB_DT_DEBUG :
s = " Debug " ;
break ;
case USB_DT_INTERFACE_ASSOCIATION :
s = " Interface Association " ;
break ;
case USB_DT_BOS :
s = " BOS " ;
break ;
case USB_DT_DEVICE_CAPABILITY :
s = " Device Capability " ;
break ;
case USB_DT_PIPE_USAGE :
s = " Pipe Usage " ;
break ;
case USB_DT_SS_ENDPOINT_COMP :
s = " SS Endpoint Companion " ;
break ;
case USB_DT_SSP_ISOC_ENDPOINT_COMP :
s = " SSP Isochronous Endpoint Companion " ;
break ;
default :
s = " UNKNOWN " ;
break ;
}
2019-08-26 12:19:27 +01:00
snprintf ( str , size , " %s %s Descriptor(Index = %d, Length = %d) " ,
2019-08-26 12:19:29 +01:00
bRequest = = USB_REQ_GET_DESCRIPTOR ? " Get " : " Set " ,
s , wValue & 0xff , wLength ) ;
2019-08-26 12:19:27 +01:00
}
static void usb_decode_get_configuration ( __u16 wLength , char * str , size_t size )
{
snprintf ( str , size , " Get Configuration(Length = %d) " , wLength ) ;
}
static void usb_decode_set_configuration ( __u8 wValue , char * str , size_t size )
{
snprintf ( str , size , " Set Configuration(Config = %d) " , wValue ) ;
}
static void usb_decode_get_intf ( __u16 wIndex , __u16 wLength , char * str ,
size_t size )
{
snprintf ( str , size , " Get Interface(Intf = %d, Length = %d) " ,
wIndex , wLength ) ;
}
static void usb_decode_set_intf ( __u8 wValue , __u16 wIndex , char * str ,
size_t size )
{
snprintf ( str , size , " Set Interface(Intf = %d, Alt.Setting = %d) " ,
wIndex , wValue ) ;
}
static void usb_decode_synch_frame ( __u16 wIndex , __u16 wLength ,
char * str , size_t size )
{
snprintf ( str , size , " Synch Frame(Endpoint = %d, Length = %d) " ,
wIndex , wLength ) ;
}
static void usb_decode_set_sel ( __u16 wLength , char * str , size_t size )
{
snprintf ( str , size , " Set SEL(Length = %d) " , wLength ) ;
}
static void usb_decode_set_isoch_delay ( __u8 wValue , char * str , size_t size )
{
snprintf ( str , size , " Set Isochronous Delay(Delay = %d ns) " , wValue ) ;
}
2021-03-08 10:52:07 +08:00
/**
* usb_decode_ctrl - Returns human readable representation of control request .
* @ str : buffer to return a human - readable representation of control request .
* This buffer should have about 200 bytes .
* @ size : size of str buffer .
* @ bRequestType : matches the USB bmRequestType field
* @ bRequest : matches the USB bRequest field
* @ wValue : matches the USB wValue field ( CPU byte order )
* @ wIndex : matches the USB wIndex field ( CPU byte order )
* @ wLength : matches the USB wLength field ( CPU byte order )
*
* Function returns decoded , formatted and human - readable description of
* control request packet .
*
* The usage scenario for this is for tracepoints , so function as a return
* use the same value as in parameters . This approach allows to use this
* function in TP_printk
*
* Important : wValue , wIndex , wLength parameters before invoking this function
* should be processed by le16_to_cpu macro .
2019-08-26 12:19:27 +01:00
*/
const char * usb_decode_ctrl ( char * str , size_t size , __u8 bRequestType ,
__u8 bRequest , __u16 wValue , __u16 wIndex ,
__u16 wLength )
{
switch ( bRequest ) {
case USB_REQ_GET_STATUS :
usb_decode_get_status ( bRequestType , wIndex , wLength , str , size ) ;
break ;
case USB_REQ_CLEAR_FEATURE :
case USB_REQ_SET_FEATURE :
usb_decode_set_clear_feature ( bRequestType , bRequest , wValue ,
wIndex , str , size ) ;
break ;
case USB_REQ_SET_ADDRESS :
usb_decode_set_address ( wValue , str , size ) ;
break ;
case USB_REQ_GET_DESCRIPTOR :
case USB_REQ_SET_DESCRIPTOR :
usb_decode_get_set_descriptor ( bRequestType , bRequest , wValue ,
wIndex , wLength , str , size ) ;
break ;
case USB_REQ_GET_CONFIGURATION :
usb_decode_get_configuration ( wLength , str , size ) ;
break ;
case USB_REQ_SET_CONFIGURATION :
usb_decode_set_configuration ( wValue , str , size ) ;
break ;
case USB_REQ_GET_INTERFACE :
usb_decode_get_intf ( wIndex , wLength , str , size ) ;
break ;
case USB_REQ_SET_INTERFACE :
usb_decode_set_intf ( wValue , wIndex , str , size ) ;
break ;
case USB_REQ_SYNCH_FRAME :
usb_decode_synch_frame ( wIndex , wLength , str , size ) ;
break ;
case USB_REQ_SET_SEL :
usb_decode_set_sel ( wLength , str , size ) ;
break ;
case USB_REQ_SET_ISOCH_DELAY :
usb_decode_set_isoch_delay ( wValue , str , size ) ;
break ;
default :
snprintf ( str , size , " %02x %02x %02x %02x %02x %02x %02x %02x " ,
bRequestType , bRequest ,
( u8 ) ( cpu_to_le16 ( wValue ) & 0xff ) ,
( u8 ) ( cpu_to_le16 ( wValue ) > > 8 ) ,
( u8 ) ( cpu_to_le16 ( wIndex ) & 0xff ) ,
( u8 ) ( cpu_to_le16 ( wIndex ) > > 8 ) ,
( u8 ) ( cpu_to_le16 ( wLength ) & 0xff ) ,
( u8 ) ( cpu_to_le16 ( wLength ) > > 8 ) ) ;
}
return str ;
}
EXPORT_SYMBOL_GPL ( usb_decode_ctrl ) ;