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_video.h> 16 17 #include "usbspec_private.h" 18 #include "usb-utils.h" 19 20 #include "listusb.h" 21 22 23 const char* 24 ClassName(int classNumber) { 25 switch (classNumber) { 26 case 0: 27 return "Per-interface classes"; 28 case USB_AUDIO_DEVICE_CLASS: 29 return "Audio"; 30 case 2: 31 return "Communication"; 32 case 3: 33 return "HID"; 34 case 5: 35 return "Physical"; 36 case 6: 37 return "Image"; 38 case 7: 39 return "Printer"; 40 case 8: 41 return "Mass storage"; 42 case 9: 43 return "Hub"; 44 case 10: 45 return "CDC-Data"; 46 case 11: 47 return "Smart card"; 48 case 13: 49 return "Content security"; 50 case USB_VIDEO_DEVICE_CLASS: 51 return "Video"; 52 case 15: 53 return "Personal Healthcare"; 54 case 0xDC: 55 return "Diagnostic device"; 56 case 0xE0: 57 return "Wireless controller"; 58 case 0xEF: 59 return "Miscellaneous"; 60 case 0xFE: 61 return "Application specific"; 62 case 0xFF: 63 return "Vendor specific"; 64 } 65 66 return "Unknown"; 67 } 68 69 70 const char* 71 SubclassName(int classNumber, int subclass) 72 { 73 if (classNumber == 0xEF) { 74 if (subclass == 0x02) 75 return " (Common)"; 76 if (subclass == 0x04) 77 return " (RNDIS)"; 78 if (subclass == 0x05) 79 return " (USB3 Vision)"; 80 if (subclass == 0x06) 81 return " (STEP)"; 82 if (subclass == 0x07) 83 return " (DVB Command Interface)"; 84 } 85 86 if (classNumber == USB_VIDEO_DEVICE_CLASS) { 87 switch (subclass) { 88 case USB_VIDEO_INTERFACE_UNDEFINED_SUBCLASS: 89 return " (Undefined)"; 90 case USB_VIDEO_INTERFACE_VIDEOCONTROL_SUBCLASS: 91 return " (Control)"; 92 case USB_VIDEO_INTERFACE_VIDEOSTREAMING_SUBCLASS: 93 return " (Streaming)"; 94 case USB_VIDEO_INTERFACE_COLLECTION_SUBCLASS: 95 return " (Collection)"; 96 } 97 } 98 99 if (classNumber == 0xFE) { 100 if (subclass == 0x01) 101 return " (Firmware Upgrade)"; 102 if (subclass == 0x02) 103 return " (IrDA)"; 104 if (subclass == 0x03) 105 return " (Test and measurement)"; 106 } 107 108 return ""; 109 } 110 111 112 const char* 113 ProtocolName(int classNumber, int subclass, int protocol) 114 { 115 switch (classNumber) { 116 case 0x09: 117 if (subclass == 0x00) 118 { 119 switch (protocol) { 120 case 0x00: 121 return " (Full speed)"; 122 case 0x01: 123 return " (Hi-speed, single TT)"; 124 case 0x02: 125 return " (Hi-speed, multiple TT)"; 126 case 0x03: 127 return " (Super speed)"; 128 } 129 } 130 case 0xE0: 131 if (subclass == 0x01 && protocol == 0x01) 132 return " (Bluetooth)"; 133 case 0xEF: 134 if (subclass == 0x02 && protocol == 0x01) 135 return " (Interface Association)"; 136 break; 137 } 138 return ""; 139 } 140 141 142 void 143 DumpDescriptorData(const usb_generic_descriptor* descriptor) 144 { 145 printf(" Type ............. 0x%02x\n", 146 descriptor->descriptor_type); 147 148 printf(" Data ............. "); 149 // len includes len and descriptor_type field 150 for (int32 i = 0; i < descriptor->length - 2; i++) 151 printf("%02x ", descriptor->data[i]); 152 printf("\n"); 153 } 154 155 156 void 157 DumpDescriptor(const usb_generic_descriptor* descriptor, 158 int classNum, int subclass) 159 { 160 switch (classNum) { 161 case USB_AUDIO_DEVICE_CLASS: 162 DumpAudioDescriptor(descriptor, subclass); 163 break; 164 case USB_VIDEO_DEVICE_CLASS: 165 DumpVideoDescriptor(descriptor, subclass); 166 break; 167 default: 168 DumpDescriptorData(descriptor); 169 break; 170 } 171 } 172 173 174 static void 175 DumpInterface(const BUSBInterface* interface) 176 { 177 if (!interface) 178 return; 179 180 printf(" Class .............. 0x%02x (%s)\n", 181 interface->Class(), ClassName(interface->Class())); 182 printf(" Subclass ........... 0x%02x%s\n", 183 interface->Subclass(), 184 SubclassName(interface->Class(), interface->Subclass())); 185 printf(" Protocol ........... 0x%02x%s\n", 186 interface->Protocol(), ProtocolName(interface->Class(), 187 interface->Subclass(), interface->Protocol())); 188 printf(" Interface String ... \"%s\"\n", 189 interface->InterfaceString()); 190 191 for (uint32 i = 0; i < interface->CountEndpoints(); i++) { 192 const BUSBEndpoint* endpoint = interface->EndpointAt(i); 193 if (!endpoint) 194 continue; 195 196 printf(" [Endpoint %" B_PRIu32 "]\n", i); 197 printf(" MaxPacketSize .... %d\n", 198 endpoint->MaxPacketSize()); 199 printf(" Interval ......... %d\n", 200 endpoint->Interval()); 201 202 if (endpoint->IsControl()) 203 printf(" Type ............. Control\n"); 204 else if (endpoint->IsBulk()) 205 printf(" Type ............. Bulk\n"); 206 else if (endpoint->IsIsochronous()) 207 printf(" Type ............. Isochronous\n"); 208 else if (endpoint->IsInterrupt()) 209 printf(" Type ............. Interrupt\n"); 210 211 if (endpoint->IsInput()) 212 printf(" Direction ........ Input\n"); 213 else 214 printf(" Direction ........ Output\n"); 215 } 216 217 char buffer[256]; 218 usb_descriptor* generic = (usb_descriptor*)buffer; 219 for (uint32 i = 0; 220 interface->OtherDescriptorAt(i, generic, 256) == B_OK; i++) { 221 printf(" [Descriptor %" B_PRIu32 "]\n", i); 222 DumpDescriptor(&generic->generic, interface->Class(), interface->Subclass()); 223 } 224 } 225 226 227 static void 228 DumpConfiguration(const BUSBConfiguration* configuration) 229 { 230 if (!configuration) 231 return; 232 233 printf(" Configuration String . \"%s\"\n", 234 configuration->ConfigurationString()); 235 for (uint32 i = 0; i < configuration->CountInterfaces(); i++) { 236 printf(" [Interface %" B_PRIu32 "]\n", i); 237 const BUSBInterface* interface = configuration->InterfaceAt(i); 238 239 for (uint32 j = 0; j < interface->CountAlternates(); j++) { 240 const BUSBInterface* alternate = interface->AlternateAt(j); 241 printf(" [Alternate %" B_PRIu32 "%s]\n", j, 242 j == interface->AlternateIndex() ? " active" : ""); 243 DumpInterface(alternate); 244 } 245 } 246 } 247 248 249 static void 250 DumpInfo(BUSBDevice& device, bool verbose) 251 { 252 const char* vendorName = NULL; 253 const char* deviceName = NULL; 254 usb_get_vendor_info(device.VendorID(), &vendorName); 255 usb_get_device_info(device.VendorID(), device.ProductID(), &deviceName); 256 257 if (!verbose) { 258 printf("%04x:%04x /dev/bus/usb%s \"%s\" \"%s\" ver. %04x\n", 259 device.VendorID(), device.ProductID(), device.Location(), 260 vendorName ? vendorName : device.ManufacturerString(), 261 deviceName ? deviceName : device.ProductString(), 262 device.Version()); 263 return; 264 } 265 266 printf("[Device /dev/bus/usb%s]\n", device.Location()); 267 printf(" Class .................. 0x%02x (%s)\n", device.Class(), 268 ClassName(device.Class())); 269 printf(" Subclass ............... 0x%02x%s\n", device.Subclass(), 270 SubclassName(device.Class(), device.Subclass())); 271 printf(" Protocol ............... 0x%02x%s\n", device.Protocol(), 272 ProtocolName(device.Class(), device.Subclass(), device.Protocol())); 273 printf(" Max Endpoint 0 Packet .. %d\n", device.MaxEndpoint0PacketSize()); 274 uint32_t version = device.USBVersion(); 275 printf(" USB Version ............ %d.%d\n", version >> 8, version & 0xFF); 276 printf(" Vendor ID .............. 0x%04x", device.VendorID()); 277 if (vendorName != NULL) 278 printf(" (%s)", vendorName); 279 printf("\n Product ID ............. 0x%04x", device.ProductID()); 280 if (deviceName != NULL) 281 printf(" (%s)", deviceName); 282 printf("\n Product Version ........ 0x%04x\n", device.Version()); 283 printf(" Manufacturer String .... \"%s\"\n", device.ManufacturerString()); 284 printf(" Product String ......... \"%s\"\n", device.ProductString()); 285 printf(" Serial Number .......... \"%s\"\n", device.SerialNumberString()); 286 287 for (uint32 i = 0; i < device.CountConfigurations(); i++) { 288 printf(" [Configuration %" B_PRIu32 "]\n", i); 289 DumpConfiguration(device.ConfigurationAt(i)); 290 } 291 292 if (device.Class() != 0x09) 293 return; 294 295 usb_hub_descriptor hubDescriptor; 296 size_t size = device.GetDescriptor(USB_DESCRIPTOR_HUB, 0, 0, 297 (void*)&hubDescriptor, sizeof(usb_hub_descriptor)); 298 if (size == sizeof(usb_hub_descriptor)) { 299 printf(" Hub ports count......... %d\n", hubDescriptor.num_ports); 300 printf(" Hub Controller Current.. %dmA\n", hubDescriptor.max_power); 301 302 for (int index = 1; index <= hubDescriptor.num_ports; index++) { 303 usb_port_status portStatus; 304 size_t actualLength = device.ControlTransfer(USB_REQTYPE_CLASS 305 | USB_REQTYPE_OTHER_IN, USB_REQUEST_GET_STATUS, 0, 306 index, sizeof(portStatus), (void*)&portStatus); 307 if (actualLength != sizeof(portStatus)) 308 continue; 309 printf(" Port %d status....... %04x.%04x%s%s%s%s%s%s%s%s\n", 310 index, portStatus.status, portStatus.change, 311 portStatus.status & PORT_STATUS_CONNECTION ? " Connect": "", 312 portStatus.status & PORT_STATUS_ENABLE ? " Enable": "", 313 portStatus.status & PORT_STATUS_SUSPEND ? " Suspend": "", 314 portStatus.status & PORT_STATUS_OVER_CURRENT ? " Overcurrent": "", 315 portStatus.status & PORT_STATUS_RESET ? " Reset": "", 316 portStatus.status & PORT_STATUS_POWER ? " Power": "", 317 portStatus.status & PORT_STATUS_TEST ? " Test": "", 318 portStatus.status & PORT_STATUS_INDICATOR ? " Indicator": ""); 319 } 320 } 321 } 322 323 324 class DumpRoster : public BUSBRoster { 325 public: 326 DumpRoster(bool verbose) 327 : fVerbose(verbose) 328 { 329 } 330 331 332 virtual status_t DeviceAdded(BUSBDevice* device) 333 { 334 DumpInfo(*device, fVerbose); 335 return B_OK; 336 } 337 338 339 virtual void DeviceRemoved(BUSBDevice* device) 340 { 341 } 342 343 private: 344 bool fVerbose; 345 }; 346 347 348 349 int 350 main(int argc, char* argv[]) 351 { 352 bool verbose = false; 353 BString devname = ""; 354 for (int i = 1; i < argc; i++) { 355 if (argv[i][0] == '-') { 356 if (argv[i][1] == 'v') 357 verbose = true; 358 else { 359 printf("Usage: listusb [-v] [device]\n\n"); 360 printf("-v: Show more detailed information including " 361 "interfaces, configurations, etc.\n\n"); 362 printf("If a device is not specified, " 363 "all devices found on the bus will be listed\n"); 364 return 1; 365 } 366 } else 367 devname = argv[i]; 368 } 369 370 if (devname.Length() > 0) { 371 BUSBDevice device(devname.String()); 372 if (device.InitCheck() < B_OK) { 373 printf("Cannot open USB device: %s\n", devname.String()); 374 return 1; 375 } else { 376 DumpInfo(device, verbose); 377 return 0; 378 } 379 } else { 380 DumpRoster roster(verbose); 381 roster.Start(); 382 roster.Stop(); 383 } 384 385 return 0; 386 } 387