diff options
author | Conrad Pankoff <deoxxa@fknsrs.biz> | 2019-08-14 18:09:53 +1000 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-08-14 13:12:54 +0200 |
commit | ecde0253750b635dad063c3d84fa2c2271f6fb48 (patch) | |
tree | 35a8c9b1ebe2346b3b95db82eee14200d94e829a | |
parent | fdcff7d15e89297e94a0bfa33b51eebf6e55e96a (diff) | |
download | serenity-ecde0253750b635dad063c3d84fa2c2271f6fb48.zip |
Libraries: Add LibPCIDB for reading PCI device information from pci.ids
-rwxr-xr-x | Kernel/makeall.sh | 1 | ||||
-rw-r--r-- | Libraries/LibPCIDB/Database.cpp | 224 | ||||
-rw-r--r-- | Libraries/LibPCIDB/Database.h | 78 | ||||
-rw-r--r-- | Libraries/LibPCIDB/Makefile | 20 | ||||
-rwxr-xr-x | Libraries/LibPCIDB/install.sh | 8 | ||||
-rw-r--r-- | Userland/Makefile | 2 |
6 files changed, 332 insertions, 1 deletions
diff --git a/Kernel/makeall.sh b/Kernel/makeall.sh index 3db26c42fe..07fc9d97c9 100755 --- a/Kernel/makeall.sh +++ b/Kernel/makeall.sh @@ -21,6 +21,7 @@ build_targets="$build_targets ../Libraries/LibM" build_targets="$build_targets ../Libraries/LibCore" build_targets="$build_targets ../Libraries/LibIPC" build_targets="$build_targets ../Libraries/LibDraw" +build_targets="$build_targets ../Libraries/LibPCIDB" build_targets="$build_targets ../Servers/SystemServer" build_targets="$build_targets ../Servers/LookupServer" build_targets="$build_targets ../Servers/WindowServer" diff --git a/Libraries/LibPCIDB/Database.cpp b/Libraries/LibPCIDB/Database.cpp new file mode 100644 index 0000000000..12aa8ea067 --- /dev/null +++ b/Libraries/LibPCIDB/Database.cpp @@ -0,0 +1,224 @@ +#include <AK/OwnPtr.h> +#include <AK/RefPtr.h> +#include <AK/StringView.h> + +#include "Database.h" + +namespace PCIDB { + +RefPtr<Database> Database::open(const StringView& file_name) +{ + auto res = adopt(*new Database(file_name)); + if (res->init() != 0) + return nullptr; + return res; +} + +const StringView Database::get_vendor(u16 vendor_id) const +{ + const auto& vendor = m_vendors.get(vendor_id); + if (!vendor.has_value()) + return ""; + return vendor.value()->name; +} + +const StringView Database::get_device(u16 vendor_id, u16 device_id) const +{ + const auto& vendor = m_vendors.get(vendor_id); + if (!vendor.has_value()) + return ""; + const auto& device = vendor.value()->devices.get(device_id); + if (!device.has_value()) + return ""; + return device.value()->name; +} + +const StringView Database::get_subsystem(u16 vendor_id, u16 device_id, u16 subvendor_id, u16 subdevice_id) const +{ + const auto& vendor = m_vendors.get(vendor_id); + if (!vendor.has_value()) + return ""; + const auto& device = vendor.value()->devices.get(device_id); + if (!device.has_value()) + return ""; + const auto& subsystem = device.value()->subsystems.get((subvendor_id << 16) + subdevice_id); + if (!subsystem.has_value()) + return ""; + return subsystem.value()->name; +} + +const StringView Database::get_class(u8 class_id) const +{ + const auto& xclass = m_classes.get(class_id); + if (!xclass.has_value()) + return ""; + return xclass.value()->name; +} + +const StringView Database::get_subclass(u8 class_id, u8 subclass_id) const +{ + const auto& xclass = m_classes.get(class_id); + if (!xclass.has_value()) + return ""; + const auto& subclass = xclass.value()->subclasses.get(subclass_id); + if (!subclass.has_value()) + return ""; + return subclass.value()->name; +} + +const StringView Database::get_programming_interface(u8 class_id, u8 subclass_id, u8 programming_interface_id) const +{ + const auto& xclass = m_classes.get(class_id); + if (!xclass.has_value()) + return ""; + const auto& subclass = xclass.value()->subclasses.get(subclass_id); + if (!subclass.has_value()) + return ""; + const auto& programming_interface = subclass.value()->programming_interfaces.get(programming_interface_id); + if (!programming_interface.has_value()) + return ""; + return programming_interface.value()->name; +} + +u8 parse_hex_digit(char digit) +{ + if (digit >= '0' && digit <= '9') + return digit - '0'; + ASSERT(digit >= 'a' && digit <= 'f'); + return 10 + (digit - 'a'); +} + +template<typename T> +T parse_hex(StringView str, int count) +{ + ASSERT(str.length() >= count); + + T res = 0; + for (int i = 0; i < count; i++) + res = (res << 4) + parse_hex_digit(str[i]); + + return res; +} + +int Database::init() +{ + if (m_ready) + return 0; + + if (!m_file.is_valid()) + return -1; + + m_view = StringView((const char*)m_file.pointer(), m_file.size()); + + ParseMode mode = ParseMode::UnknownMode; + + OwnPtr<Vendor> current_vendor = nullptr; + OwnPtr<Device> current_device = nullptr; + OwnPtr<Class> current_class = nullptr; + OwnPtr<Subclass> current_subclass = nullptr; + + auto commit_device = [&]() { + if (current_device && current_vendor) { + auto id = current_device->id; + current_vendor->devices.set(id, current_device.release_nonnull()); + } + }; + + auto commit_vendor = [&]() { + commit_device(); + if (current_vendor) { + auto id = current_vendor->id; + m_vendors.set(id, current_vendor.release_nonnull()); + } + }; + + auto commit_subclass = [&]() { + if (current_subclass && current_class) { + auto id = current_subclass->id; + current_class->subclasses.set(id, current_subclass.release_nonnull()); + } + }; + + auto commit_class = [&]() { + commit_subclass(); + if (current_class) { + auto id = current_class->id; + m_classes.set(id, current_class.release_nonnull()); + } + }; + + auto commit_all = [&]() { + commit_vendor(); + commit_class(); + }; + + auto lines = m_view.split_view('\n'); + + + for (auto& line : lines) { + if (line.length() < 2 || line[0] == '#') + continue; + + if (line[0] == 'C') { + mode = ParseMode::ClassMode; + commit_all(); + } else if ((line[0] >= '0' && line[0] <= '9') || (line[0] >= 'a' && line[0] <= 'f')) { + mode = ParseMode::VendorMode; + commit_all(); + } else if (line[0] != '\t') { + mode = ParseMode::UnknownMode; + continue; + } + + switch (mode) { + case ParseMode::VendorMode: + if (line[0] != '\t') { + commit_vendor(); + current_vendor = make<Vendor>(); + current_vendor->id = parse_hex<u16>(line, 4); + current_vendor->name = line.substring_view(6, line.length() - 6); + } else if (line[0] == '\t' && line[1] != '\t') { + commit_device(); + current_device = make<Device>(); + current_device->id = parse_hex<u16>(line.substring_view(1, line.length() - 1), 4); + current_device->name = line.substring_view(7, line.length() - 7); + } else if (line[0] == '\t' && line[1] == '\t') { + auto subsystem = make<Subsystem>(); + subsystem->vendor_id = parse_hex<u16>(line.substring_view(2, 4), 4); + subsystem->device_id = parse_hex<u16>(line.substring_view(7, 4), 4); + subsystem->name = line.substring_view(13, line.length() - 13); + current_device->subsystems.set((subsystem->vendor_id << 8) + subsystem->device_id, move(subsystem)); + } + break; + case ParseMode::ClassMode: + if (line[0] != '\t') { + commit_class(); + current_class = make<Class>(); + current_class->id = parse_hex<u8>(line.substring_view(2, 2), 2); + current_class->name = line.substring_view(6, line.length() - 6); + } else if (line[0] == '\t' && line[1] != '\t') { + commit_subclass(); + current_subclass = make<Subclass>(); + current_subclass->id = parse_hex<u8>(line.substring_view(1, 2), 2); + current_subclass->name = line.substring_view(5, line.length() - 5); + } else if (line[0] == '\t' && line[1] == '\t') { + auto programming_interface = make<ProgrammingInterface>(); + programming_interface->id = parse_hex<u8>(line.substring_view(2, 2), 2); + programming_interface->name = line.substring_view(6, line.length() - 6); + current_subclass->programming_interfaces.set(programming_interface->id, move(programming_interface)); + } + break; + default: + break; + } + } + + commit_all(); + + m_ready = true; + + + return 0; +} + +} diff --git a/Libraries/LibPCIDB/Database.h b/Libraries/LibPCIDB/Database.h new file mode 100644 index 0000000000..98935da81f --- /dev/null +++ b/Libraries/LibPCIDB/Database.h @@ -0,0 +1,78 @@ +#pragma once + +#include <AK/HashMap.h> +#include <AK/MappedFile.h> +#include <AK/NonnullOwnPtr.h> +#include <AK/RefCounted.h> +#include <AK/RefPtr.h> +#include <AK/StringView.h> + +namespace PCIDB { + +struct Subsystem { + u16 vendor_id; + u16 device_id; + StringView name; +}; + +struct Device { + u16 id; + StringView name; + HashMap<int, NonnullOwnPtr<Subsystem>> subsystems; +}; + +struct Vendor { + u16 id; + StringView name; + HashMap<int, NonnullOwnPtr<Device>> devices; +}; + +struct ProgrammingInterface { + u8 id { 0 }; + StringView name {}; +}; + +struct Subclass { + u8 id { 0 }; + StringView name {}; + HashMap<int, NonnullOwnPtr<ProgrammingInterface>> programming_interfaces; +}; + +struct Class { + u8 id { 0 }; + StringView name {}; + HashMap<int, NonnullOwnPtr<Subclass>> subclasses; +}; + +class Database : public RefCounted<Database> { +public: + static RefPtr<Database> open(const StringView& file_name); + static RefPtr<Database> open() { return open("/res/pci.ids"); }; + + const StringView get_vendor(u16 vendor_id) const; + const StringView get_device(u16 vendor_id, u16 device_id) const; + const StringView get_subsystem(u16 vendor_id, u16 device_id, u16 subvendor_id, u16 subdevice_id) const; + const StringView get_class(u8 class_id) const; + const StringView get_subclass(u8 class_id, u8 subclass_id) const; + const StringView get_programming_interface(u8 class_id, u8 subclass_id, u8 programming_interface_id) const; + +private: + Database(const StringView& file_name) + : m_file(file_name) {}; + + int init(); + + enum ParseMode { + UnknownMode, + VendorMode, + ClassMode, + }; + + MappedFile m_file {}; + StringView m_view {}; + HashMap<int, NonnullOwnPtr<Vendor>> m_vendors; + HashMap<int, NonnullOwnPtr<Class>> m_classes; + bool m_ready { false }; +}; + +} diff --git a/Libraries/LibPCIDB/Makefile b/Libraries/LibPCIDB/Makefile new file mode 100644 index 0000000000..990099fa01 --- /dev/null +++ b/Libraries/LibPCIDB/Makefile @@ -0,0 +1,20 @@ +include ../../Makefile.common + +OBJS = \ + Database.o + +LIBRARY = libpcidb.a +DEFINES += -DUSERLAND + +all: $(LIBRARY) + +$(LIBRARY): $(OBJS) + @echo "LIB $@"; $(AR) rcs $@ $(OBJS) $(LIBS) + +.cpp.o: + @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< + +-include $(OBJS:%.o=%.d) + +clean: + @echo "CLEAN"; rm -f $(LIBRARY) $(OBJS) *.d diff --git a/Libraries/LibPCIDB/install.sh b/Libraries/LibPCIDB/install.sh new file mode 100755 index 0000000000..16019bc702 --- /dev/null +++ b/Libraries/LibPCIDB/install.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -e +SERENITY_ROOT=../../ + +mkdir -p $SERENITY_ROOT/Root/usr/include/LibPCIDB/ +cp *.h $SERENITY_ROOT/Root/usr/include/LibPCIDB/ +cp libpcidb.a $SERENITY_ROOT/Root/usr/lib/ diff --git a/Userland/Makefile b/Userland/Makefile index 5da8e05a89..955eb07470 100644 --- a/Userland/Makefile +++ b/Userland/Makefile @@ -19,7 +19,7 @@ clean: $(APPS) : % : %.o $(OBJS) @echo "LD $@" - @$(LD) -o $@ $(LDFLAGS) $< -lc -lgui -ldraw -laudio -lipc -lcore + @$(LD) -o $@ $(LDFLAGS) $< -lc -lgui -ldraw -laudio -lipc -lcore -lpcidb %.o: %.cpp @echo "CXX $<" |