소스 검색

Kernel: Add /proc/bus/usb to store information about connected devices

Jesse Buhagiar 4 년 전
부모
커밋
f2ff55dd09
1개의 변경된 파일95개의 추가작업 그리고 1개의 파일을 삭제
  1. 95 1
      Kernel/FileSystem/ProcFS.cpp

+ 95 - 1
Kernel/FileSystem/ProcFS.cpp

@@ -18,6 +18,8 @@
 #include <Kernel/Debug.h>
 #include <Kernel/Devices/BlockDevice.h>
 #include <Kernel/Devices/HID/HIDManagement.h>
+#include <Kernel/Devices/USB/UHCIController.h>
+#include <Kernel/Devices/USB/USBDevice.h>
 #include <Kernel/FileSystem/Custody.h>
 #include <Kernel/FileSystem/FileBackedFileSystem.h>
 #include <Kernel/FileSystem/FileDescription.h>
@@ -49,6 +51,8 @@ namespace Kernel {
 enum ProcParentDirectory {
     PDI_AbstractRoot = 0,
     PDI_Root,
+    PDI_Root_bus,
+    PDI_Root_bus_usb,
     PDI_Root_sys,
     PDI_Root_net,
     PDI_PID,
@@ -81,6 +85,7 @@ enum ProcFileType {
     FI_Root_self, // symlink
     FI_Root_sys,  // directory
     FI_Root_net,  // directory
+    FI_Root_bus,  // directory
     __FI_Root_End,
 
     FI_Root_sys_variable,
@@ -91,6 +96,9 @@ enum ProcFileType {
     FI_Root_net_udp,
     FI_Root_net_local,
 
+    FI_Root_bus_usb,
+    FI_Root_bus_usb_device,
+
     FI_PID,
 
     __FI_PID_Start,
@@ -142,6 +150,13 @@ static inline size_t to_sys_index(const InodeIdentifier& identifier)
     return identifier.index().value() >> 16u;
 }
 
+static inline u8 to_usb_device_address(const InodeIdentifier& identifier)
+{
+    VERIFY(to_proc_parent_directory(identifier) == PDI_Root_bus_usb);
+    VERIFY(to_proc_file_type(identifier) == FI_Root_bus_usb_device);
+    return (identifier.index().value() >> 16u) & 0xff;
+}
+
 static inline InodeIdentifier to_identifier(unsigned fsid, ProcParentDirectory parent, ProcessID pid, ProcFileType proc_file_type)
 {
     return { fsid, ((unsigned)parent << 12u) | ((unsigned)pid.value() << 16u) | (unsigned)proc_file_type };
@@ -163,6 +178,12 @@ static inline InodeIdentifier sys_var_to_identifier(unsigned fsid, unsigned inde
     return { fsid, (PDI_Root_sys << 12u) | (index << 16u) | FI_Root_sys_variable };
 }
 
+static inline InodeIdentifier usb_device_address_to_identifier(unsigned fsid, unsigned device_address)
+{
+    VERIFY(device_address < 127);
+    return { fsid, (PDI_Root_bus_usb << 12u) | (device_address << 16u) | FI_Root_bus_usb_device };
+}
+
 static inline InodeIdentifier to_parent_id(const InodeIdentifier& identifier)
 {
     switch (to_proc_parent_directory(identifier)) {
@@ -173,6 +194,10 @@ static inline InodeIdentifier to_parent_id(const InodeIdentifier& identifier)
         return { identifier.fsid(), FI_Root_sys };
     case PDI_Root_net:
         return { identifier.fsid(), FI_Root_net };
+    case PDI_Root_bus:
+        return { identifier.fsid(), FI_Root_bus };
+    case PDI_Root_bus_usb:
+        return to_identifier(identifier.fsid(), PDI_Root_bus, to_pid(identifier), FI_Root_bus_usb);
     case PDI_PID:
         return to_identifier(identifier.fsid(), PDI_Root, to_pid(identifier), FI_PID);
     case PDI_PID_fd:
@@ -217,6 +242,8 @@ static inline bool is_directory(const InodeIdentifier& identifier)
     case FI_Root:
     case FI_Root_sys:
     case FI_Root_net:
+    case FI_Root_bus:
+    case FI_Root_bus_usb:
     case FI_PID:
     case FI_PID_fd:
     case FI_PID_stacks:
@@ -534,6 +561,33 @@ static bool procfs$net_tcp(InodeIdentifier, KBufferBuilder& builder)
     return true;
 }
 
+static bool procfs$usb_entry(InodeIdentifier identifier, KBufferBuilder& builder)
+{
+    u8 dev_id = to_usb_device_address(identifier);
+    auto const& device = USB::UHCIController::the().get_device_from_address(dev_id);
+    VERIFY(device); // Something has gone very wrong if this isn't true
+
+    JsonArraySerializer array { builder };
+
+    auto obj = array.add_object();
+    obj.add("usb_spec_compliance_bcd", device->device_descriptor().usb_spec_compliance_bcd);
+    obj.add("device_class", device->device_descriptor().device_class);
+    obj.add("device_sub_class", device->device_descriptor().device_sub_class);
+    obj.add("device_protocol", device->device_descriptor().device_protocol);
+    obj.add("max_packet_size", device->device_descriptor().max_packet_size);
+    obj.add("vendor_id", device->device_descriptor().vendor_id);
+    obj.add("product_id", device->device_descriptor().product_id);
+    obj.add("device_release_bcd", device->device_descriptor().device_release_bcd);
+    obj.add("manufacturer_id_descriptor_index", device->device_descriptor().manufacturer_id_descriptor_index);
+    obj.add("product_string_descriptor_index", device->device_descriptor().product_string_descriptor_index);
+    obj.add("serial_number_descriptor_index", device->device_descriptor().serial_number_descriptor_index);
+    obj.add("num_configurations", device->device_descriptor().num_configurations);
+    obj.finish();
+    array.finish();
+
+    return true;
+}
+
 static bool procfs$net_udp(InodeIdentifier, KBufferBuilder& builder)
 {
     JsonArraySerializer array { builder };
@@ -1074,6 +1128,7 @@ KResult ProcFSInode::refresh_data(FileDescription& description) const
     auto* directory_entry = fs().get_directory_entry(identifier());
 
     bool (*read_callback)(InodeIdentifier, KBufferBuilder&) = nullptr;
+
     if (directory_entry) {
         read_callback = directory_entry->read_callback;
         VERIFY(read_callback);
@@ -1097,6 +1152,9 @@ KResult ProcFSInode::refresh_data(FileDescription& description) const
                 break;
             }
             break;
+        case PDI_Root_bus_usb:
+            read_callback = procfs$usb_entry;
+            break;
         default:
             VERIFY_NOT_REACHED();
         }
@@ -1181,6 +1239,11 @@ InodeMetadata ProcFSInode::metadata() const
         return metadata;
     }
 
+    if (proc_parent_directory == PDI_Root_bus_usb) {
+        metadata.mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
+        return metadata;
+    }
+
     switch (proc_file_type) {
     case FI_Root_self:
         metadata.mode = S_IFLNK | S_IRUSR | S_IRGRP | S_IROTH;
@@ -1193,6 +1256,8 @@ InodeMetadata ProcFSInode::metadata() const
     case FI_Root:
     case FI_Root_sys:
     case FI_Root_net:
+    case FI_Root_bus:
+    case FI_Root_bus_usb:
         metadata.mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
         break;
     case FI_PID:
@@ -1335,6 +1400,24 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
         });
     } break;
 
+    case FI_Root_bus: {
+        callback({ "usb", to_identifier(fsid(), PDI_Root_bus, 0, FI_Root_bus_usb), 0 });
+        break;
+    }
+
+    case FI_Root_bus_usb: {
+        // FIXME: We currently only support 2 USB devices due to UHCI only... The controller stack should be modified
+        // to support any number of devices (this is a gross hack....)
+        for (auto port = 0; port < 2; port++) {
+            auto const& device = USB::UHCIController::the().get_device_at_port(static_cast<USB::Device::PortNumber>(port));
+            if (device == nullptr)
+                continue;
+
+            callback({ String::number(device->address()), usb_device_address_to_identifier(fsid(), device->address()), 0 });
+        }
+        break;
+    }
+
     default:
         return KSuccess;
     }
@@ -1416,6 +1499,16 @@ RefPtr<Inode> ProcFSInode::lookup(StringView name)
         return {};
     }
 
+    if (proc_file_type == FI_Root_bus) {
+        if (name == "usb")
+            return fs().get_inode(to_identifier(fsid(), PDI_Root_bus, 0, FI_Root_bus_usb));
+    }
+
+    if (proc_file_type == FI_Root_bus_usb) {
+        u8 device_address = name.to_uint().value();
+        return fs().get_inode(usb_device_address_to_identifier(fsid(), device_address));
+    }
+
     if (proc_file_type == FI_PID_fd) {
         auto name_as_number = name.to_uint();
         if (!name_as_number.has_value())
@@ -1705,6 +1798,7 @@ ProcFS::ProcFS()
     m_entries[FI_Root_profile] = { "profile", FI_Root_profile, true, procfs$profile };
     m_entries[FI_Root_sys] = { "sys", FI_Root_sys, true };
     m_entries[FI_Root_net] = { "net", FI_Root_net, false };
+    m_entries[FI_Root_bus] = { "bus", FI_Root_bus, false };
 
     m_entries[FI_Root_net_adapters] = { "adapters", FI_Root_net_adapters, false, procfs$net_adapters };
     m_entries[FI_Root_net_arp] = { "arp", FI_Root_net_arp, true, procfs$net_arp };
@@ -1726,7 +1820,7 @@ ProcFS::ProcFS()
 ProcFS::ProcFSDirectoryEntry* ProcFS::get_directory_entry(InodeIdentifier identifier) const
 {
     auto proc_file_type = to_proc_file_type(identifier);
-    if (proc_file_type != FI_Invalid && proc_file_type != FI_Root_sys_variable && proc_file_type < FI_MaxStaticFileIndex)
+    if (proc_file_type != FI_Invalid && proc_file_type != FI_Root_sys_variable && proc_file_type != FI_Root_bus_usb_device && proc_file_type < FI_MaxStaticFileIndex)
         return const_cast<ProcFSDirectoryEntry*>(&m_entries[proc_file_type]);
     return nullptr;
 }