1 /* 2 * Originally released under the Be Sample Code License. 3 * Copyright 2000, Be Incorporated. All rights reserved. 4 * 5 * Modified for Haiku by François Revol and Michael Lotz. 6 * Copyright 2007-2008, Haiku Inc. All rights reserved. 7 */ 8 9 #include <Directory.h> 10 #include <Entry.h> 11 #include <Path.h> 12 #include <String.h> 13 #include <stdio.h> 14 #include <usb/USB_audio.h> 15 #include <usb/USB_cdc.h> 16 #include <usb/USB_video.h> 17 18 #include "usbspec_private.h" 19 #include "usb-utils.h" 20 21 #include "listusb.h" 22 23 24 void 25 DumpCDCDescriptor(const usb_generic_descriptor* descriptor, int subclass) 26 { 27 if (descriptor->descriptor_type == 0x24) { 28 printf(" Type ............. CDC interface descriptor\n"); 29 printf(" Subtype .......... "); 30 switch (descriptor->data[0]) { 31 case USB_CDC_HEADER_FUNCTIONAL_DESCRIPTOR: 32 printf("Header\n"); 33 printf(" CDC Version ...... %x.%x\n", 34 descriptor->data[2], descriptor->data[1]); 35 return; 36 case USB_CDC_CM_FUNCTIONAL_DESCRIPTOR: 37 { 38 printf("Call management\n"); 39 const usb_cdc_cm_functional_descriptor* cmDesc 40 = (const usb_cdc_cm_functional_descriptor*)descriptor; 41 printf(" Capabilities ..... "); 42 bool somethingPrinted = false; 43 if ((cmDesc->capabilities & USB_CDC_CM_DOES_CALL_MANAGEMENT) != 0) { 44 printf("Call management"); 45 somethingPrinted = true; 46 } 47 if ((cmDesc->capabilities & USB_CDC_CM_OVER_DATA_INTERFACE) != 0) { 48 if (somethingPrinted) 49 printf(", "); 50 printf("Over data interface"); 51 somethingPrinted = true; 52 } 53 if (!somethingPrinted) 54 printf("None"); 55 printf("\n"); 56 printf(" Data interface ... %d\n", cmDesc->data_interface); 57 return; 58 } 59 case USB_CDC_ACM_FUNCTIONAL_DESCRIPTOR: 60 { 61 printf("Abstract control management\n"); 62 const usb_cdc_acm_functional_descriptor* acmDesc 63 = (const usb_cdc_acm_functional_descriptor*)descriptor; 64 printf(" Capabilities ..... "); 65 bool somethingPrinted = false; 66 if ((acmDesc->capabilities & USB_CDC_ACM_HAS_COMM_FEATURES) != 0) { 67 printf("Communication features"); 68 somethingPrinted = true; 69 } 70 if ((acmDesc->capabilities & USB_CDC_ACM_HAS_LINE_CONTROL) != 0) { 71 if (somethingPrinted) 72 printf(", "); 73 printf("Line control"); 74 somethingPrinted = true; 75 } 76 if ((acmDesc->capabilities & USB_CDC_ACM_HAS_SEND_BREAK) != 0) { 77 if (somethingPrinted) 78 printf(", "); 79 printf("Send break"); 80 somethingPrinted = true; 81 } 82 if ((acmDesc->capabilities & USB_CDC_ACM_HAS_NETWORK_CONNECTION) != 0) { 83 if (somethingPrinted) 84 printf(", "); 85 printf("Network connection"); 86 somethingPrinted = true; 87 } 88 if (!somethingPrinted) 89 printf("None"); 90 printf("\n"); 91 return; 92 } 93 case 0x03: 94 printf("Direct line management\n"); 95 break; 96 case 0x04: 97 printf("Telephone ringer management\n"); 98 break; 99 case 0x05: 100 printf("Telephone call and line state reporting\n"); 101 break; 102 case USB_CDC_UNION_FUNCTIONAL_DESCRIPTOR: 103 printf("Union\n"); 104 printf(" Control interface %d\n", descriptor->data[1]); 105 for (int32 i = 2; i < descriptor->length - 2; i++) 106 printf(" Subordinate ..... %d\n", descriptor->data[i]); 107 return; 108 case 0x07: 109 printf("Country selection\n"); 110 break; 111 case 0x08: 112 printf("Telephone operational mode\n"); 113 break; 114 case 0x09: 115 printf("USB Terminal\n"); 116 break; 117 case 0x0A: 118 printf("Network channel\n"); 119 break; 120 case 0x0B: 121 printf("Protocol init\n"); 122 break; 123 case 0x0C: 124 printf("Extension unit\n"); 125 break; 126 case 0x0D: 127 printf("Multi-channel management\n"); 128 break; 129 case 0x0E: 130 printf("CAPI control\n"); 131 break; 132 case 0x0F: 133 printf("Ethernet\n"); 134 break; 135 case 0x10: 136 printf("ATM\n"); 137 break; 138 case 0x11: 139 printf("Wireless handset\n"); 140 break; 141 case 0x12: 142 printf("Mobile direct line\n"); 143 break; 144 case 0x13: 145 printf("Mobile direct line detail\n"); 146 break; 147 case 0x14: 148 printf("Device management\n"); 149 break; 150 case 0x15: 151 printf("Object Exchange\n"); 152 break; 153 case 0x16: 154 printf("Command set\n"); 155 break; 156 case 0x17: 157 printf("Command set detail\n"); 158 break; 159 case 0x18: 160 printf("Telephone control\n"); 161 break; 162 case 0x19: 163 printf("Object Exchange service identifier\n"); 164 break; 165 case 0x1A: 166 printf("NCM\n"); 167 break; 168 default: 169 printf("0x%02x\n", descriptor->data[0]); 170 } 171 172 printf(" Data ............. "); 173 // len includes len and descriptor_type field 174 // start at i = 1 because we already dumped the first byte as subtype 175 for (int32 i = 1; i < descriptor->length - 2; i++) 176 printf("%02x ", descriptor->data[i]); 177 printf("\n"); 178 return; 179 } 180 181 #if 0 182 if (descriptor->descriptor_type == 0x25) { 183 printf(" Type ............. CDC endpoint descriptor\n", 184 return; 185 } 186 #endif 187 188 DumpDescriptorData(descriptor); 189 } 190 191 192 void 193 DumpDescriptorData(const usb_generic_descriptor* descriptor) 194 { 195 printf(" Type ............. 0x%02x\n", 196 descriptor->descriptor_type); 197 198 printf(" Data ............. "); 199 // len includes len and descriptor_type field 200 for (int32 i = 0; i < descriptor->length - 2; i++) 201 printf("%02x ", descriptor->data[i]); 202 printf("\n"); 203 } 204 205 206 void 207 DumpDescriptor(const usb_generic_descriptor* descriptor, 208 int classNum, int subclass) 209 { 210 switch (classNum) { 211 case USB_AUDIO_DEVICE_CLASS: 212 DumpAudioDescriptor(descriptor, subclass); 213 break; 214 case USB_VIDEO_DEVICE_CLASS: 215 DumpVideoDescriptor(descriptor, subclass); 216 break; 217 case USB_COMMUNICATION_DEVICE_CLASS: 218 case USB_COMMUNICATION_WIRELESS_DEVICE_CLASS: 219 DumpCDCDescriptor(descriptor, subclass); 220 break; 221 default: 222 DumpDescriptorData(descriptor); 223 break; 224 } 225 } 226 227 228 static void 229 DumpInterface(const BUSBInterface* interface) 230 { 231 if (!interface) 232 return; 233 234 char classInfo[128]; 235 usb_get_class_info(interface->Class(), 0, 0, classInfo, sizeof(classInfo)); 236 printf(" Class .............. 0x%02x (%s)\n", 237 interface->Class(), classInfo); 238 usb_get_class_info(interface->Class(), interface->Subclass(), 0, classInfo, sizeof(classInfo)); 239 printf(" Subclass ........... 0x%02x%s\n", 240 interface->Subclass(), classInfo); 241 usb_get_class_info(interface->Class(), interface->Subclass(), interface->Protocol(), classInfo, 242 sizeof(classInfo)); 243 printf(" Protocol ........... 0x%02x%s\n", 244 interface->Protocol(), classInfo); 245 printf(" Interface String ... \"%s\"\n", 246 interface->InterfaceString()); 247 248 for (uint32 i = 0; i < interface->CountEndpoints(); i++) { 249 const BUSBEndpoint* endpoint = interface->EndpointAt(i); 250 if (!endpoint) 251 continue; 252 253 printf(" [Endpoint %" B_PRIu32 "]\n", i); 254 printf(" MaxPacketSize .... %d\n", 255 endpoint->MaxPacketSize()); 256 printf(" Interval ......... %d\n", 257 endpoint->Interval()); 258 259 if (endpoint->IsControl()) 260 printf(" Type ............. Control\n"); 261 else if (endpoint->IsBulk()) 262 printf(" Type ............. Bulk\n"); 263 else if (endpoint->IsIsochronous()) 264 printf(" Type ............. Isochronous\n"); 265 else if (endpoint->IsInterrupt()) 266 printf(" Type ............. Interrupt\n"); 267 268 if (endpoint->IsInput()) 269 printf(" Direction ........ Input\n"); 270 else 271 printf(" Direction ........ Output\n"); 272 } 273 274 char buffer[256]; 275 usb_descriptor* generic = (usb_descriptor*)buffer; 276 for (uint32 i = 0; 277 interface->OtherDescriptorAt(i, generic, 256) == B_OK; i++) { 278 printf(" [Descriptor %" B_PRIu32 "]\n", i); 279 DumpDescriptor(&generic->generic, interface->Class(), interface->Subclass()); 280 } 281 } 282 283 284 static void 285 DumpConfiguration(const BUSBConfiguration* configuration) 286 { 287 if (!configuration) 288 return; 289 290 printf(" Configuration String . \"%s\"\n", 291 configuration->ConfigurationString()); 292 for (uint32 i = 0; i < configuration->CountInterfaces(); i++) { 293 printf(" [Interface %" B_PRIu32 "]\n", i); 294 const BUSBInterface* interface = configuration->InterfaceAt(i); 295 296 for (uint32 j = 0; j < interface->CountAlternates(); j++) { 297 const BUSBInterface* alternate = interface->AlternateAt(j); 298 printf(" [Alternate %" B_PRIu32 "%s]\n", j, 299 j == interface->AlternateIndex() ? " active" : ""); 300 DumpInterface(alternate); 301 } 302 } 303 } 304 305 306 static void 307 DumpInfo(BUSBDevice& device, bool verbose) 308 { 309 const char* vendorName = NULL; 310 const char* deviceName = NULL; 311 usb_get_vendor_info(device.VendorID(), &vendorName); 312 usb_get_device_info(device.VendorID(), device.ProductID(), &deviceName); 313 314 if (!verbose) { 315 printf("%04x:%04x /dev/bus/usb%s \"%s\" \"%s\" ver. %04x\n", 316 device.VendorID(), device.ProductID(), device.Location(), 317 vendorName ? vendorName : device.ManufacturerString(), 318 deviceName ? deviceName : device.ProductString(), 319 device.Version()); 320 return; 321 } 322 323 char classInfo[128]; 324 printf("[Device /dev/bus/usb%s]\n", device.Location()); 325 usb_get_class_info(device.Class(), 0, 0, classInfo, sizeof(classInfo)); 326 printf(" Class .................. 0x%02x (%s)\n", device.Class(), classInfo); 327 usb_get_class_info(device.Class(), device.Subclass(), 0, classInfo, sizeof(classInfo)); 328 printf(" Subclass ............... 0x%02x%s\n", device.Subclass(), classInfo); 329 usb_get_class_info(device.Class(), device.Subclass(), device.Protocol(), classInfo, 330 sizeof(classInfo)); 331 printf(" Protocol ............... 0x%02x%s\n", device.Protocol(), classInfo); 332 printf(" Max Endpoint 0 Packet .. %d\n", device.MaxEndpoint0PacketSize()); 333 uint32_t version = device.USBVersion(); 334 printf(" USB Version ............ %d.%d\n", version >> 8, version & 0xFF); 335 printf(" Vendor ID .............. 0x%04x", device.VendorID()); 336 if (vendorName != NULL) 337 printf(" (%s)", vendorName); 338 printf("\n Product ID ............. 0x%04x", device.ProductID()); 339 if (deviceName != NULL) 340 printf(" (%s)", deviceName); 341 printf("\n Product Version ........ 0x%04x\n", device.Version()); 342 printf(" Manufacturer String .... \"%s\"\n", device.ManufacturerString()); 343 printf(" Product String ......... \"%s\"\n", device.ProductString()); 344 printf(" Serial Number .......... \"%s\"\n", device.SerialNumberString()); 345 346 for (uint32 i = 0; i < device.CountConfigurations(); i++) { 347 printf(" [Configuration %" B_PRIu32 "]\n", i); 348 DumpConfiguration(device.ConfigurationAt(i)); 349 } 350 351 if (device.Class() != 0x09) 352 return; 353 354 usb_hub_descriptor hubDescriptor; 355 size_t size = device.GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0, 356 (void*)&hubDescriptor, sizeof(usb_hub_descriptor)); 357 if (size == sizeof(usb_hub_descriptor)) { 358 printf(" Hub ports count......... %d\n", hubDescriptor.num_ports); 359 printf(" Hub Controller Current.. %dmA\n", hubDescriptor.max_power); 360 361 for (int index = 1; index <= hubDescriptor.num_ports; index++) { 362 usb_port_status portStatus; 363 size_t actualLength = device.ControlTransfer(USB_REQTYPE_CLASS 364 | USB_REQTYPE_OTHER_IN, USB_REQUEST_GET_STATUS, 0, 365 index, sizeof(portStatus), (void*)&portStatus); 366 if (actualLength != sizeof(portStatus)) 367 continue; 368 printf(" Port %d status....... %04x.%04x%s%s%s%s%s%s%s%s\n", 369 index, portStatus.status, portStatus.change, 370 portStatus.status & PORT_STATUS_CONNECTION ? " Connect": "", 371 portStatus.status & PORT_STATUS_ENABLE ? " Enable": "", 372 portStatus.status & PORT_STATUS_SUSPEND ? " Suspend": "", 373 portStatus.status & PORT_STATUS_OVER_CURRENT ? " Overcurrent": "", 374 portStatus.status & PORT_STATUS_RESET ? " Reset": "", 375 portStatus.status & PORT_STATUS_POWER ? " Power": "", 376 portStatus.status & PORT_STATUS_TEST ? " Test": "", 377 portStatus.status & PORT_STATUS_INDICATOR ? " Indicator": ""); 378 } 379 } 380 } 381 382 383 class DumpRoster : public BUSBRoster { 384 public: 385 DumpRoster(bool verbose) 386 : fVerbose(verbose) 387 { 388 } 389 390 391 virtual status_t DeviceAdded(BUSBDevice* device) 392 { 393 DumpInfo(*device, fVerbose); 394 return B_OK; 395 } 396 397 398 virtual void DeviceRemoved(BUSBDevice* device) 399 { 400 } 401 402 private: 403 bool fVerbose; 404 }; 405 406 407 408 int 409 main(int argc, char* argv[]) 410 { 411 bool verbose = false; 412 BString devname = ""; 413 for (int i = 1; i < argc; i++) { 414 if (argv[i][0] == '-') { 415 if (argv[i][1] == 'v') 416 verbose = true; 417 else { 418 printf("Usage: listusb [-v] [device]\n\n"); 419 printf("-v: Show more detailed information including " 420 "interfaces, configurations, etc.\n\n"); 421 printf("If a device is not specified, " 422 "all devices found on the bus will be listed\n"); 423 return 1; 424 } 425 } else 426 devname = argv[i]; 427 } 428 429 if (devname.Length() > 0) { 430 BUSBDevice device(devname.String()); 431 if (device.InitCheck() < B_OK) { 432 printf("Cannot open USB device: %s\n", devname.String()); 433 return 1; 434 } else { 435 DumpInfo(device, verbose); 436 return 0; 437 } 438 } else { 439 DumpRoster roster(verbose); 440 roster.Start(); 441 roster.Stop(); 442 } 443 444 return 0; 445 } 446