root/src/apps/devices/DeviceACPI.cpp
/*
 * Copyright 2008-2022 Haiku Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Rob Gill <rrobgill@protonmail.com>
 *              Alexander von Gluck (kallisti5)
 */


#include "DeviceACPI.h"

#include <sstream>
#include <stdlib.h>

#include <Catalog.h>

extern "C" {
#include "acpipnpids.h"
#include "isapnpids.h"
}

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "DeviceACPI"


void
acpi_get_vendor_info(const char* vendorID, const char **vendorName)
{
        for (size_t i = 0; i < ACPIPNP_DEVTABLE_LEN; i++) {
                if (strncmp(acpipnp_devids[i].VenId, vendorID, strlen(acpipnp_devids[i].VenId)) == 0) {
                        *vendorName = acpipnp_devids[i].VenName;
                        return;
                }
        }
        *vendorName = NULL;
}


void
isapnp_get_device_info(const char* deviceId, const char **deviceName)
{
        for (size_t i = 0; i < ISA_DEVTABLE_LEN; i++) {
                if (strncmp(isapnp_devids[i].id, deviceId, strlen(isapnp_devids[i].id)) == 0) {
                        *deviceName = isapnp_devids[i].devname;
                        return;
                }
        }
        *deviceName = NULL;
}


DeviceACPI::DeviceACPI(Device* parent)
        :
        Device(parent)
{
}


DeviceACPI::~DeviceACPI()
{
}


void
DeviceACPI::InitFromAttributes()
{
        BString nodeACPIPath;
        BString rootACPIPath;
        BString nodeACPIHid;
        BString nodeACPICid;
        BString deviceName;
        const char* hidDevName = NULL;
        const char* cidDevName = NULL;

        rootACPIPath = nodeACPIPath = GetAttribute("acpi/path").fValue;
        nodeACPIHid = GetAttribute("acpi/hid").fValue;
        nodeACPICid = GetAttribute("acpi/cid").fValue;

        // Grab just the root node info
        // We grab 6 characters to not identify sub nodes of root node
        rootACPIPath.Truncate(6);
        // Grab node leaf name
        nodeACPIPath.Remove(0, nodeACPIPath.FindLast(".") + 1);

        fCategory = (Category)CAT_ACPI;

        isapnp_get_device_info(nodeACPIHid.String(), &hidDevName);
        isapnp_get_device_info(nodeACPICid.String(), &cidDevName);

        // Identify Predefined root namespaces (ACPI Spec 4.0a, p162)
        if (rootACPIPath == "\\_SB_") {
                deviceName = B_TRANSLATE("ACPI System Bus");
        } else if (rootACPIPath == "\\_TZ_") {
                deviceName = B_TRANSLATE("ACPI Thermal Zone");
        } else if (rootACPIPath == "\\_PR_.") {
                // This allows to localize apostrophes, too
                BString string(B_TRANSLATE("ACPI Processor Namespace '%2'"));
                string.ReplaceFirst("%2", nodeACPIPath);
                // each CPU node is considered a root node
                deviceName << string.String();
        } else if (rootACPIPath == "\\_SI_") {
                deviceName = B_TRANSLATE("ACPI System Indicator");
        } else if (hidDevName != NULL) {
                deviceName << hidDevName;
        } else if (cidDevName != NULL) {
                deviceName << cidDevName;
        } else if (nodeACPIPath != "") {
                // This allows to localize apostrophes, too
                BString string(B_TRANSLATE("ACPI node '%1'"));
                string.ReplaceFirst("%1", nodeACPIPath);
                deviceName << string.String();
        } else if (nodeACPIPath == "" && nodeACPIHid != "") {
                // Handle ACPI HID entries that do not return a path
                nodeACPIHid.Remove(0, nodeACPIHid.FindLast("_") + 1);
                BString string(B_TRANSLATE("ACPI Button '%1'")); 
                string.ReplaceFirst("%1", nodeACPIHid); 
                deviceName << string.String();
        } else {
                BString string(B_TRANSLATE("ACPI <unknown>"));
                deviceName << string.String();
        }

        // Fetch ManufacturerName
        const char* vendorName = NULL;
        BString manufacturerLabel;
        if (nodeACPIHid != "")
                acpi_get_vendor_info(nodeACPIHid, &vendorName);
        if (vendorName == NULL) {
                manufacturerLabel << B_TRANSLATE("Unknown");
        } else {
                manufacturerLabel << vendorName;
        };

        SetAttribute(B_TRANSLATE("Device name"), deviceName.String());
        SetAttribute(B_TRANSLATE("Manufacturer"), manufacturerLabel);
        BString outlineName;
        if (vendorName != NULL)
                outlineName << vendorName << " ";
        outlineName << deviceName;
        SetText(outlineName.String());
}