mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 10:22:45 +00:00 
			
		
		
		
	 6e19ab2bbc
			
		
	
	
		6e19ab2bbc
		
	
	
	
	
		
			
			We have a new, improved string type coming up in AK (OOM aware, no null state), and while it's going to use UTF-8, the name UTF8String is a mouthful - so let's free up the String name by renaming the existing class. Making the old one have an annoying name will hopefully also help with quick adoption :^)
		
			
				
	
	
		
			169 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #include <AK/ByteBuffer.h>
 | |
| #include <AK/DeprecatedString.h>
 | |
| #include <AK/FixedArray.h>
 | |
| #include <AK/JsonArray.h>
 | |
| #include <AK/JsonObject.h>
 | |
| #include <AK/LexicalPath.h>
 | |
| #include <LibCore/ArgsParser.h>
 | |
| #include <LibCore/DirIterator.h>
 | |
| #include <LibCore/Stream.h>
 | |
| #include <LibCore/System.h>
 | |
| #include <LibMain/Main.h>
 | |
| #include <LibUSBDB/Database.h>
 | |
| #include <stdio.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| ErrorOr<int> serenity_main(Main::Arguments arguments)
 | |
| {
 | |
|     bool print_verbose = false;
 | |
|     bool flag_show_numerical = false;
 | |
|     Core::ArgsParser args;
 | |
|     args.set_general_help("List USB devices.");
 | |
|     args.add_option(print_verbose, "Print all device descriptors", "verbose", 'v');
 | |
|     args.add_option(flag_show_numerical, "Show numerical IDs", "numerical", 'n');
 | |
|     args.parse(arguments);
 | |
| 
 | |
|     if (!flag_show_numerical)
 | |
|         TRY(Core::System::unveil("/res/usb.ids", "r"));
 | |
|     TRY(Core::System::pledge("stdio rpath"));
 | |
|     TRY(Core::System::unveil("/sys/bus/usb", "r"));
 | |
|     TRY(Core::System::unveil(nullptr, nullptr));
 | |
| 
 | |
|     Core::DirIterator usb_devices("/sys/bus/usb", Core::DirIterator::SkipDots);
 | |
| 
 | |
|     RefPtr<USBDB::Database> usb_db;
 | |
|     if (!flag_show_numerical) {
 | |
|         usb_db = USBDB::Database::open();
 | |
|         if (!usb_db) {
 | |
|             warnln("Failed to open usb.ids");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     while (usb_devices.has_next()) {
 | |
|         auto full_path = LexicalPath(usb_devices.next_full_path());
 | |
| 
 | |
|         auto proc_usb_device = Core::Stream::File::open(full_path.string(), Core::Stream::OpenMode::Read);
 | |
|         if (proc_usb_device.is_error()) {
 | |
|             warnln("Failed to open {}: {}", full_path.string(), proc_usb_device.error());
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         auto contents = proc_usb_device.value()->read_all();
 | |
|         if (contents.is_error()) {
 | |
|             warnln("Failed to read {}: {}", full_path.string(), contents.error());
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         auto json_or_error = JsonValue::from_string(contents.value());
 | |
|         if (json_or_error.is_error()) {
 | |
|             warnln("Failed to decode JSON: {}", json_or_error.error());
 | |
|             continue;
 | |
|         }
 | |
|         auto json = json_or_error.release_value();
 | |
| 
 | |
|         json.as_array().for_each([usb_db, print_verbose](auto& value) {
 | |
|             auto& device_descriptor = value.as_object();
 | |
| 
 | |
|             auto device_address = device_descriptor.get("device_address"sv).to_u32();
 | |
|             auto vendor_id = device_descriptor.get("vendor_id"sv).to_u32();
 | |
|             auto product_id = device_descriptor.get("product_id"sv).to_u32();
 | |
| 
 | |
|             if (usb_db) {
 | |
|                 StringView vendor_string = usb_db->get_vendor(vendor_id);
 | |
|                 StringView device_string = usb_db->get_device(vendor_id, product_id);
 | |
|                 if (device_string.is_empty())
 | |
|                     device_string = "Unknown Device"sv;
 | |
| 
 | |
|                 outln("Device {}: ID {:04x}:{:04x} {} {}", device_address, vendor_id, product_id, vendor_string, device_string);
 | |
|             } else {
 | |
|                 outln("Device {}: ID {:04x}:{:04x}", device_address, vendor_id, product_id);
 | |
|             }
 | |
| 
 | |
|             if (print_verbose) {
 | |
|                 outln("Device Descriptor");
 | |
|                 outln("  bLength            {}", device_descriptor.get("length"sv).to_u32());
 | |
|                 outln("  bDescriptorType    {}", device_descriptor.get("descriptor_type"sv).to_u32());
 | |
|                 outln("  bcdUSB             {}", device_descriptor.get("usb_spec_compliance_bcd"sv).to_u32());
 | |
|                 outln("  bDeviceClass       {}", device_descriptor.get("device_class"sv).to_u32());
 | |
|                 outln("  bDeviceSubClass    {}", device_descriptor.get("device_sub_class"sv).to_u32());
 | |
|                 outln("  bDeviceProtocol    {}", device_descriptor.get("device_protocol"sv).to_u32());
 | |
|                 outln("  bMaxPacketSize     {}", device_descriptor.get("max_packet_size"sv).to_u32());
 | |
|                 if (usb_db) {
 | |
|                     StringView vendor_string = usb_db->get_vendor(vendor_id);
 | |
|                     StringView device_string = usb_db->get_device(vendor_id, product_id);
 | |
|                     outln("  idVendor           0x{:04x} {}", device_descriptor.get("vendor_id"sv).to_u32(), vendor_string);
 | |
|                     outln("  idProduct          0x{:04x} {}", device_descriptor.get("product_id"sv).to_u32(), device_string);
 | |
|                 } else {
 | |
|                     outln("  idVendor           0x{:04x}", device_descriptor.get("vendor_id"sv).to_u32());
 | |
|                     outln("  idProduct          0x{:04x}", device_descriptor.get("product_id"sv).to_u32());
 | |
|                 }
 | |
|                 outln("  bcdDevice          {}", device_descriptor.get("device_release_bcd"sv).to_u32());
 | |
|                 outln("  iManufacturer      {}", device_descriptor.get("manufacturer_id_descriptor_index"sv).to_u32());
 | |
|                 outln("  iProduct           {}", device_descriptor.get("product_string_descriptor_index"sv).to_u32());
 | |
|                 outln("  iSerial            {}", device_descriptor.get("serial_number_descriptor_index"sv).to_u32());
 | |
|                 outln("  bNumConfigurations {}", device_descriptor.get("num_configurations"sv).to_u32());
 | |
| 
 | |
|                 auto const& configuration_descriptors = value.as_object().get("configurations"sv);
 | |
|                 configuration_descriptors.as_array().for_each([&](auto& config_value) {
 | |
|                     auto const& configuration_descriptor = config_value.as_object();
 | |
|                     outln("  Configuration Descriptor:");
 | |
|                     outln("    bLength          {}", configuration_descriptor.get("length"sv).as_u32());
 | |
|                     outln("    bDescriptorType  {}", configuration_descriptor.get("descriptor_type"sv).as_u32());
 | |
|                     outln("    wTotalLength     {}", configuration_descriptor.get("total_length"sv).as_u32());
 | |
|                     outln("    bNumInterfaces   {}", configuration_descriptor.get("number_of_interfaces"sv).as_u32());
 | |
|                     outln("    bmAttributes     0x{:02x}", configuration_descriptor.get("attributes_bitmap"sv).as_u32());
 | |
|                     outln("    MaxPower         {}mA", configuration_descriptor.get("max_power"sv).as_u32() * 2u);
 | |
| 
 | |
|                     auto const& interface_descriptors = config_value.as_object().get("interfaces"sv);
 | |
|                     interface_descriptors.as_array().for_each([&](auto& interface_value) {
 | |
|                         auto const& interface_descriptor = interface_value.as_object();
 | |
|                         auto const interface_class_code = interface_descriptor.get("interface_class_code"sv).to_u32();
 | |
|                         auto const interface_subclass_code = interface_descriptor.get("interface_sub_class_code"sv).to_u32();
 | |
|                         auto const interface_protocol_code = interface_descriptor.get("interface_protocol"sv).to_u32();
 | |
| 
 | |
|                         outln("    Interface Descriptor:");
 | |
|                         outln("      bLength            {}", interface_descriptor.get("length"sv).to_u32());
 | |
|                         outln("      bDescriptorType    {}", interface_descriptor.get("descriptor_type"sv).to_u32());
 | |
|                         outln("      bInterfaceNumber   {}", interface_descriptor.get("interface_number"sv).to_u32());
 | |
|                         outln("      bAlternateSetting  {}", interface_descriptor.get("alternate_setting"sv).to_u32());
 | |
|                         outln("      bNumEndpoints      {}", interface_descriptor.get("num_endpoints"sv).to_u32());
 | |
|                         if (usb_db) {
 | |
|                             auto const interface_class = usb_db->get_class(interface_class_code);
 | |
|                             auto const interface_subclass = usb_db->get_subclass(interface_class_code, interface_subclass_code);
 | |
|                             auto const interface_protocol = usb_db->get_protocol(interface_class_code, interface_subclass_code, interface_protocol_code);
 | |
|                             outln("      bInterfaceClass    {} {}", interface_class_code, interface_class);
 | |
|                             outln("      bInterfaceSubClass {} {}", interface_subclass_code, interface_subclass);
 | |
|                             outln("      bInterfaceProtocol {} {}", interface_protocol_code, interface_protocol);
 | |
|                         } else {
 | |
|                             outln("      bInterfaceClass    {}", interface_class_code);
 | |
|                             outln("      bInterfaceSubClass {}", interface_subclass_code);
 | |
|                             outln("      bInterfaceProtocol {}", interface_protocol_code);
 | |
|                         }
 | |
|                         outln("      iInterface         {}", interface_descriptor.get("interface_string_desc_index"sv).to_u32());
 | |
| 
 | |
|                         auto const& endpoint_descriptors = interface_value.as_object().get("endpoints"sv);
 | |
|                         endpoint_descriptors.as_array().for_each([&](auto& endpoint_value) {
 | |
|                             auto const& endpoint_descriptor = endpoint_value.as_object();
 | |
|                             auto const endpoint_address = endpoint_descriptor.get("endpoint_address"sv).to_u32();
 | |
|                             outln("      Endpoint Descriptor:");
 | |
|                             outln("        bLength            {}", endpoint_descriptor.get("length"sv).to_u32());
 | |
|                             outln("        bDescriptorType    {}", endpoint_descriptor.get("descriptor_type"sv).to_u32());
 | |
|                             outln("        bEndpointAddress   0x{:02x} EP {} {}", endpoint_address, (endpoint_address & 0xFu), ((endpoint_address & 0x80u) ? "IN" : "OUT"));
 | |
|                             outln("        bmAttributes       0x{:02x}", endpoint_descriptor.get("attribute_bitmap"sv).to_u32());
 | |
|                             outln("        wMaxPacketSize     0x{:04x}", endpoint_descriptor.get("max_packet_size"sv).to_u32());
 | |
|                             outln("        bInterval          {}", endpoint_descriptor.get("polling_interval"sv).to_u32());
 | |
|                         });
 | |
|                     });
 | |
|                 });
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 |