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 const char* 25 ClassName(int classNumber) { 26 switch (classNumber) { 27 case 0: 28 return "Per-interface classes"; 29 case USB_AUDIO_DEVICE_CLASS: 30 return "Audio"; 31 case 2: 32 return "Communication"; 33 case 3: 34 return "HID"; 35 case 5: 36 return "Physical"; 37 case 6: 38 return "Image"; 39 case 7: 40 return "Printer"; 41 case 8: 42 return "Mass storage"; 43 case 9: 44 return "Hub"; 45 case 10: 46 return "CDC-Data"; 47 case 11: 48 return "Smart card"; 49 case 13: 50 return "Content security"; 51 case USB_VIDEO_DEVICE_CLASS: 52 return "Video"; 53 case 15: 54 return "Personal Healthcare"; 55 case 0xDC: 56 return "Diagnostic device"; 57 case 0xE0: 58 return "Wireless controller"; 59 case 0xEF: 60 return "Miscellaneous"; 61 case 0xFE: 62 return "Application specific"; 63 case 0xFF: 64 return "Vendor specific"; 65 } 66 67 return "Unknown"; 68 } 69 70 71 const char* 72 SubclassName(int classNumber, int subclass) 73 { 74 if (classNumber == 0xEF) { 75 if (subclass == 0x02) 76 return " (Common)"; 77 if (subclass == 0x04) 78 return " (RNDIS)"; 79 if (subclass == 0x05) 80 return " (USB3 Vision)"; 81 if (subclass == 0x06) 82 return " (STEP)"; 83 if (subclass == 0x07) 84 return " (DVB Command Interface)"; 85 } 86 87 if (classNumber == USB_VIDEO_DEVICE_CLASS) { 88 switch (subclass) { 89 case USB_VIDEO_INTERFACE_UNDEFINED_SUBCLASS: 90 return " (Undefined)"; 91 case USB_VIDEO_INTERFACE_VIDEOCONTROL_SUBCLASS: 92 return " (Control)"; 93 case USB_VIDEO_INTERFACE_VIDEOSTREAMING_SUBCLASS: 94 return " (Streaming)"; 95 case USB_VIDEO_INTERFACE_COLLECTION_SUBCLASS: 96 return " (Collection)"; 97 } 98 } 99 100 if (classNumber == 0xFE) { 101 if (subclass == 0x01) 102 return " (Firmware Upgrade)"; 103 if (subclass == 0x02) 104 return " (IrDA)"; 105 if (subclass == 0x03) 106 return " (Test and measurement)"; 107 } 108 109 return ""; 110 } 111 112 113 const char* 114 ProtocolName(int classNumber, int subclass, int protocol) 115 { 116 switch (classNumber) { 117 case 0x09: 118 if (subclass == 0x00) 119 { 120 switch (protocol) { 121 case 0x00: 122 return " (Full speed)"; 123 case 0x01: 124 return " (Hi-speed, single TT)"; 125 case 0x02: 126 return " (Hi-speed, multiple TT)"; 127 case 0x03: 128 return " (Super speed)"; 129 } 130 } 131 case 0xE0: 132 if (subclass == 0x01 && protocol == 0x01) 133 return " (Bluetooth control)"; 134 if (subclass == 0x01 && protocol == 0x02) 135 return " (UWB Radio)"; 136 if (subclass == 0x01 && protocol == 0x03) 137 return " (RNDIS control)"; 138 if (subclass == 0x01 && protocol == 0x04) 139 return " (Bluetooth AMP)"; 140 if (subclass == 0x02 && protocol == 0x01) 141 return " (Host wire adapter)"; 142 if (subclass == 0x02 && protocol == 0x02) 143 return " (Device wire adapter)"; 144 if (subclass == 0x02 && protocol == 0x03) 145 return " (Device wire isochronous)"; 146 case 0xEF: 147 if (subclass == 0x01 && protocol == 0x01) 148 return " (Microsoft Active Sync)"; 149 if (subclass == 0x01 && protocol == 0x02) 150 return " (Palm Sync)"; 151 if (subclass == 0x02 && protocol == 0x01) 152 return " (Interface Association)"; 153 if (subclass == 0x02 && protocol == 0x02) 154 return " (Wire adapter multifunction peripheral)"; 155 if (subclass == 0x03 && protocol == 0x01) 156 return " (Cable based association framework)"; 157 if (subclass == 0x04 && protocol == 0x01) 158 return " (RNDIS Ethernet)"; 159 if (subclass == 0x04 && protocol == 0x02) 160 return " (RNDIS Wifi)"; 161 if (subclass == 0x04 && protocol == 0x03) 162 return " (RNDIS WiMAX)"; 163 if (subclass == 0x04 && protocol == 0x04) 164 return " (RNDIS WWAN)"; 165 if (subclass == 0x04 && protocol == 0x05) 166 return " (RNDIS raw IPv4)"; 167 if (subclass == 0x04 && protocol == 0x06) 168 return " (RNDIS raw IPv6)"; 169 if (subclass == 0x04 && protocol == 0x07) 170 return " (RNDIS GPRS)"; 171 if (subclass == 0x05 && protocol == 0x00) 172 return " (USB3 vision control)"; 173 if (subclass == 0x05 && protocol == 0x01) 174 return " (USB3 vision event)"; 175 if (subclass == 0x05 && protocol == 0x02) 176 return " (USB3 vision streaming)"; 177 if (subclass == 0x06 && protocol == 0x01) 178 return " (STEP)"; 179 if (subclass == 0x06 && protocol == 0x02) 180 return " (STEP RAW)"; 181 if (subclass == 0x07 && protocol == 0x01) 182 return " (DVB Command Interface in IAD)"; 183 if (subclass == 0x07 && protocol == 0x02) 184 return " (DVB Command Interface in interface descriptor)"; 185 if (subclass == 0x07 && protocol == 0x03) 186 return " (Media interface in interface descriptor)"; 187 break; 188 } 189 return ""; 190 } 191 192 193 void 194 DumpCDCDescriptor(const usb_generic_descriptor* descriptor, int subclass) 195 { 196 if (descriptor->descriptor_type == 0x24) { 197 printf(" Type ............. CDC interface descriptor\n"); 198 printf(" Subtype .......... "); 199 switch (descriptor->data[0]) { 200 case USB_CDC_HEADER_FUNCTIONAL_DESCRIPTOR: 201 printf("Header\n"); 202 printf(" CDC Version ...... %x.%x\n", 203 descriptor->data[2], descriptor->data[1]); 204 return; 205 case USB_CDC_CM_FUNCTIONAL_DESCRIPTOR: 206 { 207 printf("Call management\n"); 208 const usb_cdc_cm_functional_descriptor* cmDesc 209 = (const usb_cdc_cm_functional_descriptor*)descriptor; 210 printf(" Capabilities ..... "); 211 bool somethingPrinted = false; 212 if ((cmDesc->capabilities & USB_CDC_CM_DOES_CALL_MANAGEMENT) != 0) { 213 printf("Call management"); 214 somethingPrinted = true; 215 } 216 if ((cmDesc->capabilities & USB_CDC_CM_OVER_DATA_INTERFACE) != 0) { 217 if (somethingPrinted) 218 printf(", "); 219 printf("Over data interface"); 220 somethingPrinted = true; 221 } 222 if (!somethingPrinted) 223 printf("None"); 224 printf("\n"); 225 printf(" Data interface ... %d\n", cmDesc->data_interface); 226 return; 227 } 228 case USB_CDC_ACM_FUNCTIONAL_DESCRIPTOR: 229 { 230 printf("Abstract control management\n"); 231 const usb_cdc_acm_functional_descriptor* acmDesc 232 = (const usb_cdc_acm_functional_descriptor*)descriptor; 233 printf(" Capabilities ..... "); 234 bool somethingPrinted = false; 235 if ((acmDesc->capabilities & USB_CDC_ACM_HAS_COMM_FEATURES) != 0) { 236 printf("Communication features"); 237 somethingPrinted = true; 238 } 239 if ((acmDesc->capabilities & USB_CDC_ACM_HAS_LINE_CONTROL) != 0) { 240 if (somethingPrinted) 241 printf(", "); 242 printf("Line control"); 243 somethingPrinted = true; 244 } 245 if ((acmDesc->capabilities & USB_CDC_ACM_HAS_SEND_BREAK) != 0) { 246 if (somethingPrinted) 247 printf(", "); 248 printf("Send break"); 249 somethingPrinted = true; 250 } 251 if ((acmDesc->capabilities & USB_CDC_ACM_HAS_NETWORK_CONNECTION) != 0) { 252 if (somethingPrinted) 253 printf(", "); 254 printf("Network connection"); 255 somethingPrinted = true; 256 } 257 if (!somethingPrinted) 258 printf("None"); 259 printf("\n"); 260 return; 261 } 262 case 0x03: 263 printf("Direct line management\n"); 264 break; 265 case 0x04: 266 printf("Telephone ringer management\n"); 267 break; 268 case 0x05: 269 printf("Telephone call and line state reporting\n"); 270 break; 271 case USB_CDC_UNION_FUNCTIONAL_DESCRIPTOR: 272 printf("Union\n"); 273 printf(" Control interface %d\n", descriptor->data[1]); 274 for (int32 i = 2; i < descriptor->length - 2; i++) 275 printf(" Subordinate ..... %d\n", descriptor->data[i]); 276 return; 277 case 0x07: 278 printf("Country selection\n"); 279 break; 280 case 0x08: 281 printf("Telephone operational mode\n"); 282 break; 283 case 0x09: 284 printf("USB Terminal\n"); 285 break; 286 case 0x0A: 287 printf("Network channel\n"); 288 break; 289 case 0x0B: 290 printf("Protocol init\n"); 291 break; 292 case 0x0C: 293 printf("Extension unit\n"); 294 break; 295 case 0x0D: 296 printf("Multi-channel management\n"); 297 break; 298 case 0x0E: 299 printf("CAPI control\n"); 300 break; 301 case 0x0F: 302 printf("Ethernet\n"); 303 break; 304 case 0x10: 305 printf("ATM\n"); 306 break; 307 case 0x11: 308 printf("Wireless handset\n"); 309 break; 310 case 0x12: 311 printf("Mobile direct line\n"); 312 break; 313 case 0x13: 314 printf("Mobile direct line detail\n"); 315 break; 316 case 0x14: 317 printf("Device management\n"); 318 break; 319 case 0x15: 320 printf("Object Exchange\n"); 321 break; 322 case 0x16: 323 printf("Command set\n"); 324 break; 325 case 0x17: 326 printf("Command set detail\n"); 327 break; 328 case 0x18: 329 printf("Telephone control\n"); 330 break; 331 case 0x19: 332 printf("Object Exchange service identifier\n"); 333 break; 334 case 0x1A: 335 printf("NCM\n"); 336 break; 337 default: 338 printf("0x%02x\n", descriptor->data[0]); 339 } 340 341 printf(" Data ............. "); 342 // len includes len and descriptor_type field 343 // start at i = 1 because we already dumped the first byte as subtype 344 for (int32 i = 1; i < descriptor->length - 2; i++) 345 printf("%02x ", descriptor->data[i]); 346 printf("\n"); 347 return; 348 } 349 350 #if 0 351 if (descriptor->descriptor_type == 0x25) { 352 printf(" Type ............. CDC endpoint descriptor\n", 353 return; 354 } 355 #endif 356 357 DumpDescriptorData(descriptor); 358 } 359 360 361 void 362 DumpDescriptorData(const usb_generic_descriptor* descriptor) 363 { 364 printf(" Type ............. 0x%02x\n", 365 descriptor->descriptor_type); 366 367 printf(" Data ............. "); 368 // len includes len and descriptor_type field 369 for (int32 i = 0; i < descriptor->length - 2; i++) 370 printf("%02x ", descriptor->data[i]); 371 printf("\n"); 372 } 373 374 375 void 376 DumpDescriptor(const usb_generic_descriptor* descriptor, 377 int classNum, int subclass) 378 { 379 switch (classNum) { 380 case USB_AUDIO_DEVICE_CLASS: 381 DumpAudioDescriptor(descriptor, subclass); 382 break; 383 case USB_VIDEO_DEVICE_CLASS: 384 DumpVideoDescriptor(descriptor, subclass); 385 break; 386 case USB_COMMUNICATION_DEVICE_CLASS: 387 case USB_COMMUNICATION_WIRELESS_DEVICE_CLASS: 388 DumpCDCDescriptor(descriptor, subclass); 389 break; 390 default: 391 DumpDescriptorData(descriptor); 392 break; 393 } 394 } 395 396 397 static void 398 DumpInterface(const BUSBInterface* interface) 399 { 400 if (!interface) 401 return; 402 403 printf(" Class .............. 0x%02x (%s)\n", 404 interface->Class(), ClassName(interface->Class())); 405 printf(" Subclass ........... 0x%02x%s\n", 406 interface->Subclass(), 407 SubclassName(interface->Class(), interface->Subclass())); 408 printf(" Protocol ........... 0x%02x%s\n", 409 interface->Protocol(), ProtocolName(interface->Class(), 410 interface->Subclass(), interface->Protocol())); 411 printf(" Interface String ... \"%s\"\n", 412 interface->InterfaceString()); 413 414 for (uint32 i = 0; i < interface->CountEndpoints(); i++) { 415 const BUSBEndpoint* endpoint = interface->EndpointAt(i); 416 if (!endpoint) 417 continue; 418 419 printf(" [Endpoint %" B_PRIu32 "]\n", i); 420 printf(" MaxPacketSize .... %d\n", 421 endpoint->MaxPacketSize()); 422 printf(" Interval ......... %d\n", 423 endpoint->Interval()); 424 425 if (endpoint->IsControl()) 426 printf(" Type ............. Control\n"); 427 else if (endpoint->IsBulk()) 428 printf(" Type ............. Bulk\n"); 429 else if (endpoint->IsIsochronous()) 430 printf(" Type ............. Isochronous\n"); 431 else if (endpoint->IsInterrupt()) 432 printf(" Type ............. Interrupt\n"); 433 434 if (endpoint->IsInput()) 435 printf(" Direction ........ Input\n"); 436 else 437 printf(" Direction ........ Output\n"); 438 } 439 440 char buffer[256]; 441 usb_descriptor* generic = (usb_descriptor*)buffer; 442 for (uint32 i = 0; 443 interface->OtherDescriptorAt(i, generic, 256) == B_OK; i++) { 444 printf(" [Descriptor %" B_PRIu32 "]\n", i); 445 DumpDescriptor(&generic->generic, interface->Class(), interface->Subclass()); 446 } 447 } 448 449 450 static void 451 DumpConfiguration(const BUSBConfiguration* configuration) 452 { 453 if (!configuration) 454 return; 455 456 printf(" Configuration String . \"%s\"\n", 457 configuration->ConfigurationString()); 458 for (uint32 i = 0; i < configuration->CountInterfaces(); i++) { 459 printf(" [Interface %" B_PRIu32 "]\n", i); 460 const BUSBInterface* interface = configuration->InterfaceAt(i); 461 462 for (uint32 j = 0; j < interface->CountAlternates(); j++) { 463 const BUSBInterface* alternate = interface->AlternateAt(j); 464 printf(" [Alternate %" B_PRIu32 "%s]\n", j, 465 j == interface->AlternateIndex() ? " active" : ""); 466 DumpInterface(alternate); 467 } 468 } 469 } 470 471 472 static void 473 DumpInfo(BUSBDevice& device, bool verbose) 474 { 475 const char* vendorName = NULL; 476 const char* deviceName = NULL; 477 usb_get_vendor_info(device.VendorID(), &vendorName); 478 usb_get_device_info(device.VendorID(), device.ProductID(), &deviceName); 479 480 if (!verbose) { 481 printf("%04x:%04x /dev/bus/usb%s \"%s\" \"%s\" ver. %04x\n", 482 device.VendorID(), device.ProductID(), device.Location(), 483 vendorName ? vendorName : device.ManufacturerString(), 484 deviceName ? deviceName : device.ProductString(), 485 device.Version()); 486 return; 487 } 488 489 printf("[Device /dev/bus/usb%s]\n", device.Location()); 490 printf(" Class .................. 0x%02x (%s)\n", device.Class(), 491 ClassName(device.Class())); 492 printf(" Subclass ............... 0x%02x%s\n", device.Subclass(), 493 SubclassName(device.Class(), device.Subclass())); 494 printf(" Protocol ............... 0x%02x%s\n", device.Protocol(), 495 ProtocolName(device.Class(), device.Subclass(), device.Protocol())); 496 printf(" Max Endpoint 0 Packet .. %d\n", device.MaxEndpoint0PacketSize()); 497 uint32_t version = device.USBVersion(); 498 printf(" USB Version ............ %d.%d\n", version >> 8, version & 0xFF); 499 printf(" Vendor ID .............. 0x%04x", device.VendorID()); 500 if (vendorName != NULL) 501 printf(" (%s)", vendorName); 502 printf("\n Product ID ............. 0x%04x", device.ProductID()); 503 if (deviceName != NULL) 504 printf(" (%s)", deviceName); 505 printf("\n Product Version ........ 0x%04x\n", device.Version()); 506 printf(" Manufacturer String .... \"%s\"\n", device.ManufacturerString()); 507 printf(" Product String ......... \"%s\"\n", device.ProductString()); 508 printf(" Serial Number .......... \"%s\"\n", device.SerialNumberString()); 509 510 for (uint32 i = 0; i < device.CountConfigurations(); i++) { 511 printf(" [Configuration %" B_PRIu32 "]\n", i); 512 DumpConfiguration(device.ConfigurationAt(i)); 513 } 514 515 if (device.Class() != 0x09) 516 return; 517 518 usb_hub_descriptor hubDescriptor; 519 size_t size = device.GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0, 520 (void*)&hubDescriptor, sizeof(usb_hub_descriptor)); 521 if (size == sizeof(usb_hub_descriptor)) { 522 printf(" Hub ports count......... %d\n", hubDescriptor.num_ports); 523 printf(" Hub Controller Current.. %dmA\n", hubDescriptor.max_power); 524 525 for (int index = 1; index <= hubDescriptor.num_ports; index++) { 526 usb_port_status portStatus; 527 size_t actualLength = device.ControlTransfer(USB_REQTYPE_CLASS 528 | USB_REQTYPE_OTHER_IN, USB_REQUEST_GET_STATUS, 0, 529 index, sizeof(portStatus), (void*)&portStatus); 530 if (actualLength != sizeof(portStatus)) 531 continue; 532 printf(" Port %d status....... %04x.%04x%s%s%s%s%s%s%s%s\n", 533 index, portStatus.status, portStatus.change, 534 portStatus.status & PORT_STATUS_CONNECTION ? " Connect": "", 535 portStatus.status & PORT_STATUS_ENABLE ? " Enable": "", 536 portStatus.status & PORT_STATUS_SUSPEND ? " Suspend": "", 537 portStatus.status & PORT_STATUS_OVER_CURRENT ? " Overcurrent": "", 538 portStatus.status & PORT_STATUS_RESET ? " Reset": "", 539 portStatus.status & PORT_STATUS_POWER ? " Power": "", 540 portStatus.status & PORT_STATUS_TEST ? " Test": "", 541 portStatus.status & PORT_STATUS_INDICATOR ? " Indicator": ""); 542 } 543 } 544 } 545 546 547 class DumpRoster : public BUSBRoster { 548 public: 549 DumpRoster(bool verbose) 550 : fVerbose(verbose) 551 { 552 } 553 554 555 virtual status_t DeviceAdded(BUSBDevice* device) 556 { 557 DumpInfo(*device, fVerbose); 558 return B_OK; 559 } 560 561 562 virtual void DeviceRemoved(BUSBDevice* device) 563 { 564 } 565 566 private: 567 bool fVerbose; 568 }; 569 570 571 572 int 573 main(int argc, char* argv[]) 574 { 575 bool verbose = false; 576 BString devname = ""; 577 for (int i = 1; i < argc; i++) { 578 if (argv[i][0] == '-') { 579 if (argv[i][1] == 'v') 580 verbose = true; 581 else { 582 printf("Usage: listusb [-v] [device]\n\n"); 583 printf("-v: Show more detailed information including " 584 "interfaces, configurations, etc.\n\n"); 585 printf("If a device is not specified, " 586 "all devices found on the bus will be listed\n"); 587 return 1; 588 } 589 } else 590 devname = argv[i]; 591 } 592 593 if (devname.Length() > 0) { 594 BUSBDevice device(devname.String()); 595 if (device.InitCheck() < B_OK) { 596 printf("Cannot open USB device: %s\n", devname.String()); 597 return 1; 598 } else { 599 DumpInfo(device, verbose); 600 return 0; 601 } 602 } else { 603 DumpRoster roster(verbose); 604 roster.Start(); 605 roster.Stop(); 606 } 607 608 return 0; 609 } 610