Pawel Laszczak | 91f255a | 2019-08-26 12:19:27 +0100 | [diff] [blame^] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /** |
| 3 | * Common USB debugging functions |
| 4 | * |
| 5 | * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com |
| 6 | * |
| 7 | * Authors: Felipe Balbi <balbi@ti.com>, |
| 8 | * Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| 9 | */ |
| 10 | |
| 11 | #include <linux/usb/ch9.h> |
| 12 | |
| 13 | static void usb_decode_get_status(__u8 bRequestType, __u16 wIndex, |
| 14 | __u16 wLength, char *str, size_t size) |
| 15 | { |
| 16 | switch (bRequestType & USB_RECIP_MASK) { |
| 17 | case USB_RECIP_DEVICE: |
| 18 | snprintf(str, size, "Get Device Status(Length = %d)", wLength); |
| 19 | break; |
| 20 | case USB_RECIP_INTERFACE: |
| 21 | snprintf(str, size, |
| 22 | "Get Interface Status(Intf = %d, Length = %d)", |
| 23 | wIndex, wLength); |
| 24 | break; |
| 25 | case USB_RECIP_ENDPOINT: |
| 26 | snprintf(str, size, "Get Endpoint Status(ep%d%s)", |
| 27 | wIndex & ~USB_DIR_IN, |
| 28 | wIndex & USB_DIR_IN ? "in" : "out"); |
| 29 | break; |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | static void usb_decode_set_clear_feature(__u8 bRequestType, __u8 bRequest, |
| 34 | __u16 wValue, __u16 wIndex, |
| 35 | char *str, size_t size) |
| 36 | { |
| 37 | switch (bRequestType & USB_RECIP_MASK) { |
| 38 | case USB_RECIP_DEVICE: |
| 39 | snprintf(str, size, "%s Device Feature(%s%s)", |
| 40 | bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", |
| 41 | ({char *s; |
| 42 | switch (wValue) { |
| 43 | case USB_DEVICE_SELF_POWERED: |
| 44 | s = "Self Powered"; |
| 45 | break; |
| 46 | case USB_DEVICE_REMOTE_WAKEUP: |
| 47 | s = "Remote Wakeup"; |
| 48 | break; |
| 49 | case USB_DEVICE_TEST_MODE: |
| 50 | s = "Test Mode"; |
| 51 | break; |
| 52 | case USB_DEVICE_U1_ENABLE: |
| 53 | s = "U1 Enable"; |
| 54 | break; |
| 55 | case USB_DEVICE_U2_ENABLE: |
| 56 | s = "U2 Enable"; |
| 57 | break; |
| 58 | case USB_DEVICE_LTM_ENABLE: |
| 59 | s = "LTM Enable"; |
| 60 | break; |
| 61 | default: |
| 62 | s = "UNKNOWN"; |
| 63 | } s; }), |
| 64 | wValue == USB_DEVICE_TEST_MODE ? |
| 65 | ({ char *s; |
| 66 | switch (wIndex) { |
| 67 | case TEST_J: |
| 68 | s = ": TEST_J"; |
| 69 | break; |
| 70 | case TEST_K: |
| 71 | s = ": TEST_K"; |
| 72 | break; |
| 73 | case TEST_SE0_NAK: |
| 74 | s = ": TEST_SE0_NAK"; |
| 75 | break; |
| 76 | case TEST_PACKET: |
| 77 | s = ": TEST_PACKET"; |
| 78 | break; |
| 79 | case TEST_FORCE_EN: |
| 80 | s = ": TEST_FORCE_EN"; |
| 81 | break; |
| 82 | default: |
| 83 | s = ": UNKNOWN"; |
| 84 | } s; }) : ""); |
| 85 | break; |
| 86 | case USB_RECIP_INTERFACE: |
| 87 | snprintf(str, size, "%s Interface Feature(%s)", |
| 88 | bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", |
| 89 | wValue == USB_INTRF_FUNC_SUSPEND ? |
| 90 | "Function Suspend" : "UNKNOWN"); |
| 91 | break; |
| 92 | case USB_RECIP_ENDPOINT: |
| 93 | snprintf(str, size, "%s Endpoint Feature(%s ep%d%s)", |
| 94 | bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set", |
| 95 | wValue == USB_ENDPOINT_HALT ? "Halt" : "UNKNOWN", |
| 96 | wIndex & ~USB_DIR_IN, |
| 97 | wIndex & USB_DIR_IN ? "in" : "out"); |
| 98 | break; |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | static void usb_decode_set_address(__u16 wValue, char *str, size_t size) |
| 103 | { |
| 104 | snprintf(str, size, "Set Address(Addr = %02x)", wValue); |
| 105 | } |
| 106 | |
| 107 | static void usb_decode_get_set_descriptor(__u8 bRequestType, __u8 bRequest, |
| 108 | __u16 wValue, __u16 wIndex, |
| 109 | __u16 wLength, char *str, size_t size) |
| 110 | { |
| 111 | snprintf(str, size, "%s %s Descriptor(Index = %d, Length = %d)", |
| 112 | bRequest == USB_REQ_GET_DESCRIPTOR ? "Get" : "Set", |
| 113 | ({ char *s; |
| 114 | switch (wValue >> 8) { |
| 115 | case USB_DT_DEVICE: |
| 116 | s = "Device"; |
| 117 | break; |
| 118 | case USB_DT_CONFIG: |
| 119 | s = "Configuration"; |
| 120 | break; |
| 121 | case USB_DT_STRING: |
| 122 | s = "String"; |
| 123 | break; |
| 124 | case USB_DT_INTERFACE: |
| 125 | s = "Interface"; |
| 126 | break; |
| 127 | case USB_DT_ENDPOINT: |
| 128 | s = "Endpoint"; |
| 129 | break; |
| 130 | case USB_DT_DEVICE_QUALIFIER: |
| 131 | s = "Device Qualifier"; |
| 132 | break; |
| 133 | case USB_DT_OTHER_SPEED_CONFIG: |
| 134 | s = "Other Speed Config"; |
| 135 | break; |
| 136 | case USB_DT_INTERFACE_POWER: |
| 137 | s = "Interface Power"; |
| 138 | break; |
| 139 | case USB_DT_OTG: |
| 140 | s = "OTG"; |
| 141 | break; |
| 142 | case USB_DT_DEBUG: |
| 143 | s = "Debug"; |
| 144 | break; |
| 145 | case USB_DT_INTERFACE_ASSOCIATION: |
| 146 | s = "Interface Association"; |
| 147 | break; |
| 148 | case USB_DT_BOS: |
| 149 | s = "BOS"; |
| 150 | break; |
| 151 | case USB_DT_DEVICE_CAPABILITY: |
| 152 | s = "Device Capability"; |
| 153 | break; |
| 154 | case USB_DT_PIPE_USAGE: |
| 155 | s = "Pipe Usage"; |
| 156 | break; |
| 157 | case USB_DT_SS_ENDPOINT_COMP: |
| 158 | s = "SS Endpoint Companion"; |
| 159 | break; |
| 160 | case USB_DT_SSP_ISOC_ENDPOINT_COMP: |
| 161 | s = "SSP Isochronous Endpoint Companion"; |
| 162 | break; |
| 163 | default: |
| 164 | s = "UNKNOWN"; |
| 165 | break; |
| 166 | } s; }), wValue & 0xff, wLength); |
| 167 | } |
| 168 | |
| 169 | static void usb_decode_get_configuration(__u16 wLength, char *str, size_t size) |
| 170 | { |
| 171 | snprintf(str, size, "Get Configuration(Length = %d)", wLength); |
| 172 | } |
| 173 | |
| 174 | static void usb_decode_set_configuration(__u8 wValue, char *str, size_t size) |
| 175 | { |
| 176 | snprintf(str, size, "Set Configuration(Config = %d)", wValue); |
| 177 | } |
| 178 | |
| 179 | static void usb_decode_get_intf(__u16 wIndex, __u16 wLength, char *str, |
| 180 | size_t size) |
| 181 | { |
| 182 | snprintf(str, size, "Get Interface(Intf = %d, Length = %d)", |
| 183 | wIndex, wLength); |
| 184 | } |
| 185 | |
| 186 | static void usb_decode_set_intf(__u8 wValue, __u16 wIndex, char *str, |
| 187 | size_t size) |
| 188 | { |
| 189 | snprintf(str, size, "Set Interface(Intf = %d, Alt.Setting = %d)", |
| 190 | wIndex, wValue); |
| 191 | } |
| 192 | |
| 193 | static void usb_decode_synch_frame(__u16 wIndex, __u16 wLength, |
| 194 | char *str, size_t size) |
| 195 | { |
| 196 | snprintf(str, size, "Synch Frame(Endpoint = %d, Length = %d)", |
| 197 | wIndex, wLength); |
| 198 | } |
| 199 | |
| 200 | static void usb_decode_set_sel(__u16 wLength, char *str, size_t size) |
| 201 | { |
| 202 | snprintf(str, size, "Set SEL(Length = %d)", wLength); |
| 203 | } |
| 204 | |
| 205 | static void usb_decode_set_isoch_delay(__u8 wValue, char *str, size_t size) |
| 206 | { |
| 207 | snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", wValue); |
| 208 | } |
| 209 | |
| 210 | /** |
| 211 | * usb_decode_ctrl - returns a string representation of ctrl request |
| 212 | */ |
| 213 | const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType, |
| 214 | __u8 bRequest, __u16 wValue, __u16 wIndex, |
| 215 | __u16 wLength) |
| 216 | { |
| 217 | switch (bRequest) { |
| 218 | case USB_REQ_GET_STATUS: |
| 219 | usb_decode_get_status(bRequestType, wIndex, wLength, str, size); |
| 220 | break; |
| 221 | case USB_REQ_CLEAR_FEATURE: |
| 222 | case USB_REQ_SET_FEATURE: |
| 223 | usb_decode_set_clear_feature(bRequestType, bRequest, wValue, |
| 224 | wIndex, str, size); |
| 225 | break; |
| 226 | case USB_REQ_SET_ADDRESS: |
| 227 | usb_decode_set_address(wValue, str, size); |
| 228 | break; |
| 229 | case USB_REQ_GET_DESCRIPTOR: |
| 230 | case USB_REQ_SET_DESCRIPTOR: |
| 231 | usb_decode_get_set_descriptor(bRequestType, bRequest, wValue, |
| 232 | wIndex, wLength, str, size); |
| 233 | break; |
| 234 | case USB_REQ_GET_CONFIGURATION: |
| 235 | usb_decode_get_configuration(wLength, str, size); |
| 236 | break; |
| 237 | case USB_REQ_SET_CONFIGURATION: |
| 238 | usb_decode_set_configuration(wValue, str, size); |
| 239 | break; |
| 240 | case USB_REQ_GET_INTERFACE: |
| 241 | usb_decode_get_intf(wIndex, wLength, str, size); |
| 242 | break; |
| 243 | case USB_REQ_SET_INTERFACE: |
| 244 | usb_decode_set_intf(wValue, wIndex, str, size); |
| 245 | break; |
| 246 | case USB_REQ_SYNCH_FRAME: |
| 247 | usb_decode_synch_frame(wIndex, wLength, str, size); |
| 248 | break; |
| 249 | case USB_REQ_SET_SEL: |
| 250 | usb_decode_set_sel(wLength, str, size); |
| 251 | break; |
| 252 | case USB_REQ_SET_ISOCH_DELAY: |
| 253 | usb_decode_set_isoch_delay(wValue, str, size); |
| 254 | break; |
| 255 | default: |
| 256 | snprintf(str, size, "%02x %02x %02x %02x %02x %02x %02x %02x", |
| 257 | bRequestType, bRequest, |
| 258 | (u8)(cpu_to_le16(wValue) & 0xff), |
| 259 | (u8)(cpu_to_le16(wValue) >> 8), |
| 260 | (u8)(cpu_to_le16(wIndex) & 0xff), |
| 261 | (u8)(cpu_to_le16(wIndex) >> 8), |
| 262 | (u8)(cpu_to_le16(wLength) & 0xff), |
| 263 | (u8)(cpu_to_le16(wLength) >> 8)); |
| 264 | } |
| 265 | |
| 266 | return str; |
| 267 | } |
| 268 | EXPORT_SYMBOL_GPL(usb_decode_ctrl); |