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