Serenity Operating System
at master 169 lines 10 kB view raw
1/* 2 * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/ByteBuffer.h> 8#include <AK/DeprecatedString.h> 9#include <AK/FixedArray.h> 10#include <AK/JsonArray.h> 11#include <AK/JsonObject.h> 12#include <AK/LexicalPath.h> 13#include <LibCore/ArgsParser.h> 14#include <LibCore/DirIterator.h> 15#include <LibCore/File.h> 16#include <LibCore/System.h> 17#include <LibMain/Main.h> 18#include <LibUSBDB/Database.h> 19#include <stdio.h> 20#include <unistd.h> 21 22ErrorOr<int> serenity_main(Main::Arguments arguments) 23{ 24 bool print_verbose = false; 25 bool flag_show_numerical = false; 26 Core::ArgsParser args; 27 args.set_general_help("List USB devices."); 28 args.add_option(print_verbose, "Print all device descriptors", "verbose", 'v'); 29 args.add_option(flag_show_numerical, "Show numerical IDs", "numerical", 'n'); 30 args.parse(arguments); 31 32 if (!flag_show_numerical) 33 TRY(Core::System::unveil("/res/usb.ids", "r")); 34 TRY(Core::System::pledge("stdio rpath")); 35 TRY(Core::System::unveil("/sys/bus/usb", "r")); 36 TRY(Core::System::unveil(nullptr, nullptr)); 37 38 Core::DirIterator usb_devices("/sys/bus/usb", Core::DirIterator::SkipDots); 39 40 RefPtr<USBDB::Database> usb_db; 41 if (!flag_show_numerical) { 42 usb_db = USBDB::Database::open(); 43 if (!usb_db) { 44 warnln("Failed to open usb.ids"); 45 } 46 } 47 48 while (usb_devices.has_next()) { 49 auto full_path = LexicalPath(usb_devices.next_full_path()); 50 51 auto proc_usb_device = Core::File::open(full_path.string(), Core::File::OpenMode::Read); 52 if (proc_usb_device.is_error()) { 53 warnln("Failed to open {}: {}", full_path.string(), proc_usb_device.error()); 54 continue; 55 } 56 57 auto contents = proc_usb_device.value()->read_until_eof(); 58 if (contents.is_error()) { 59 warnln("Failed to read {}: {}", full_path.string(), contents.error()); 60 continue; 61 } 62 63 auto json_or_error = JsonValue::from_string(contents.value()); 64 if (json_or_error.is_error()) { 65 warnln("Failed to decode JSON: {}", json_or_error.error()); 66 continue; 67 } 68 auto json = json_or_error.release_value(); 69 70 json.as_array().for_each([usb_db, print_verbose](auto& value) { 71 auto& device_descriptor = value.as_object(); 72 73 auto device_address = device_descriptor.get_u32("device_address"sv).value_or(0); 74 auto vendor_id = device_descriptor.get_u32("vendor_id"sv).value_or(0); 75 auto product_id = device_descriptor.get_u32("product_id"sv).value_or(0); 76 77 if (usb_db) { 78 StringView vendor_string = usb_db->get_vendor(vendor_id); 79 StringView device_string = usb_db->get_device(vendor_id, product_id); 80 if (device_string.is_empty()) 81 device_string = "Unknown Device"sv; 82 83 outln("Device {}: ID {:04x}:{:04x} {} {}", device_address, vendor_id, product_id, vendor_string, device_string); 84 } else { 85 outln("Device {}: ID {:04x}:{:04x}", device_address, vendor_id, product_id); 86 } 87 88 if (print_verbose) { 89 outln("Device Descriptor"); 90 outln(" bLength {}", device_descriptor.get_u32("length"sv).value_or(0)); 91 outln(" bDescriptorType {}", device_descriptor.get_u32("descriptor_type"sv).value_or(0)); 92 outln(" bcdUSB {}", device_descriptor.get_u32("usb_spec_compliance_bcd"sv).value_or(0)); 93 outln(" bDeviceClass {}", device_descriptor.get_u32("device_class"sv).value_or(0)); 94 outln(" bDeviceSubClass {}", device_descriptor.get_u32("device_sub_class"sv).value_or(0)); 95 outln(" bDeviceProtocol {}", device_descriptor.get_u32("device_protocol"sv).value_or(0)); 96 outln(" bMaxPacketSize {}", device_descriptor.get_u32("max_packet_size"sv).value_or(0)); 97 if (usb_db) { 98 StringView vendor_string = usb_db->get_vendor(vendor_id); 99 StringView device_string = usb_db->get_device(vendor_id, product_id); 100 outln(" idVendor 0x{:04x} {}", device_descriptor.get_u32("vendor_id"sv).value_or(0), vendor_string); 101 outln(" idProduct 0x{:04x} {}", device_descriptor.get_u32("product_id"sv).value_or(0), device_string); 102 } else { 103 outln(" idVendor 0x{:04x}", device_descriptor.get_u32("vendor_id"sv).value_or(0)); 104 outln(" idProduct 0x{:04x}", device_descriptor.get_u32("product_id"sv).value_or(0)); 105 } 106 outln(" bcdDevice {}", device_descriptor.get_u32("device_release_bcd"sv).value_or(0)); 107 outln(" iManufacturer {}", device_descriptor.get_u32("manufacturer_id_descriptor_index"sv).value_or(0)); 108 outln(" iProduct {}", device_descriptor.get_u32("product_string_descriptor_index"sv).value_or(0)); 109 outln(" iSerial {}", device_descriptor.get_u32("serial_number_descriptor_index"sv).value_or(0)); 110 outln(" bNumConfigurations {}", device_descriptor.get_u32("num_configurations"sv).value_or(0)); 111 112 auto const& configuration_descriptors = value.as_object().get_array("configurations"sv).value(); 113 configuration_descriptors.for_each([&](auto& config_value) { 114 auto const& configuration_descriptor = config_value.as_object(); 115 outln(" Configuration Descriptor:"); 116 outln(" bLength {}", configuration_descriptor.get_u32("length"sv).value_or(0)); 117 outln(" bDescriptorType {}", configuration_descriptor.get_u32("descriptor_type"sv).value_or(0)); 118 outln(" wTotalLength {}", configuration_descriptor.get_u32("total_length"sv).value_or(0)); 119 outln(" bNumInterfaces {}", configuration_descriptor.get_u32("number_of_interfaces"sv).value_or(0)); 120 outln(" bmAttributes 0x{:02x}", configuration_descriptor.get_u32("attributes_bitmap"sv).value_or(0)); 121 outln(" MaxPower {}mA", configuration_descriptor.get_u32("max_power"sv).value_or(0) * 2u); 122 123 auto const& interface_descriptors = config_value.as_object().get_array("interfaces"sv).value(); 124 interface_descriptors.for_each([&](auto& interface_value) { 125 auto const& interface_descriptor = interface_value.as_object(); 126 auto const interface_class_code = interface_descriptor.get_u32("interface_class_code"sv).value_or(0); 127 auto const interface_subclass_code = interface_descriptor.get_u32("interface_sub_class_code"sv).value_or(0); 128 auto const interface_protocol_code = interface_descriptor.get_u32("interface_protocol"sv).value_or(0); 129 130 outln(" Interface Descriptor:"); 131 outln(" bLength {}", interface_descriptor.get_u32("length"sv).value_or(0)); 132 outln(" bDescriptorType {}", interface_descriptor.get_u32("descriptor_type"sv).value_or(0)); 133 outln(" bInterfaceNumber {}", interface_descriptor.get_u32("interface_number"sv).value_or(0)); 134 outln(" bAlternateSetting {}", interface_descriptor.get_u32("alternate_setting"sv).value_or(0)); 135 outln(" bNumEndpoints {}", interface_descriptor.get_u32("num_endpoints"sv).value_or(0)); 136 if (usb_db) { 137 auto const interface_class = usb_db->get_class(interface_class_code); 138 auto const interface_subclass = usb_db->get_subclass(interface_class_code, interface_subclass_code); 139 auto const interface_protocol = usb_db->get_protocol(interface_class_code, interface_subclass_code, interface_protocol_code); 140 outln(" bInterfaceClass {} {}", interface_class_code, interface_class); 141 outln(" bInterfaceSubClass {} {}", interface_subclass_code, interface_subclass); 142 outln(" bInterfaceProtocol {} {}", interface_protocol_code, interface_protocol); 143 } else { 144 outln(" bInterfaceClass {}", interface_class_code); 145 outln(" bInterfaceSubClass {}", interface_subclass_code); 146 outln(" bInterfaceProtocol {}", interface_protocol_code); 147 } 148 outln(" iInterface {}", interface_descriptor.get_u32("interface_string_desc_index"sv).value_or(0)); 149 150 auto const& endpoint_descriptors = interface_value.as_object().get_array("endpoints"sv).value(); 151 endpoint_descriptors.for_each([&](auto& endpoint_value) { 152 auto const& endpoint_descriptor = endpoint_value.as_object(); 153 auto const endpoint_address = endpoint_descriptor.get_u32("endpoint_address"sv).value_or(0); 154 outln(" Endpoint Descriptor:"); 155 outln(" bLength {}", endpoint_descriptor.get_u32("length"sv).value_or(0)); 156 outln(" bDescriptorType {}", endpoint_descriptor.get_u32("descriptor_type"sv).value_or(0)); 157 outln(" bEndpointAddress 0x{:02x} EP {} {}", endpoint_address, (endpoint_address & 0xFu), ((endpoint_address & 0x80u) ? "IN" : "OUT")); 158 outln(" bmAttributes 0x{:02x}", endpoint_descriptor.get_u32("attribute_bitmap"sv).value_or(0)); 159 outln(" wMaxPacketSize 0x{:04x}", endpoint_descriptor.get_u32("max_packet_size"sv).value_or(0)); 160 outln(" bInterval {}", endpoint_descriptor.get_u32("polling_interval"sv).value_or(0)); 161 }); 162 }); 163 }); 164 } 165 }); 166 } 167 168 return 0; 169}