/* * Copyright (C) 2026 oxmc / PawletOS * SPDX-License-Identifier: Apache-2.0 */ #include "detect.h" #include #include #include #include #include #include namespace pawlet::hwupdate { namespace { namespace fs = std::filesystem; struct UsbDev { std::string vid; // lowercase hex, e.g. "1209" std::string pid; // lowercase hex std::string node; // /dev/bus/usb/BBB/DDD }; std::string ReadTrimmed(const std::string& path) { std::string s; if (!android::base::ReadFileToString(path, &s)) return {}; return android::base::Trim(s); } // Enumerate connected USB devices from sysfs. std::vector EnumUsb() { std::vector out; const std::string base = "/sys/bus/usb/devices"; std::error_code ec; if (!fs::exists(base, ec)) return out; for (const auto& entry : fs::directory_iterator(base, ec)) { const std::string dir = entry.path().string(); std::string vid = ReadTrimmed(dir + "/idVendor"); std::string pid = ReadTrimmed(dir + "/idProduct"); if (vid.empty() || pid.empty()) continue; // hubs/interfaces, skip UsbDev d; d.vid = android::base::Trim(vid); d.pid = android::base::Trim(pid); std::string bus = ReadTrimmed(dir + "/busnum"); std::string dev = ReadTrimmed(dir + "/devnum"); if (!bus.empty() && !dev.empty()) { char node[64]; snprintf(node, sizeof(node), "/dev/bus/usb/%03d/%03d", atoi(bus.c_str()), atoi(dev.c_str())); d.node = node; } out.push_back(std::move(d)); } return out; } bool UsbMatch(const std::vector& devs, const std::string& vid, const std::string& pid, std::string* node) { for (const auto& d : devs) { if (android::base::EqualsIgnoreCase(d.vid, vid) && android::base::EqualsIgnoreCase(d.pid, pid)) { if (node) *node = d.node; return true; } } return false; } } // namespace std::vector Detect(const Manifest& manifest) { std::vector usb = EnumUsb(); std::vector out; for (const auto& prod : manifest.products) { for (const auto& comp : prod.components) { DetectedComponent dc; dc.product = ∏ dc.comp = ∁ if (!comp.usbVendorId.empty() && !comp.usbProductId.empty()) { std::string node; if (UsbMatch(usb, comp.usbVendorId, comp.usbProductId, &node)) { dc.present = true; dc.transport = "usb"; dc.usbVendorId = comp.usbVendorId; dc.usbProductId = comp.usbProductId; dc.devPath = node; } } // TODO: device-tree / i2c / spi detectors go here. if (dc.present) { LOG(INFO) << "hwupdate: detected " << comp.id << " on " << dc.transport; } out.push_back(std::move(dc)); } } return out; } } // namespace pawlet::hwupdate