Serenity Operating System
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}