blob: b99fb770647a14f9d7853a4bde2acb653be8a4b0 [file]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// An RAII wrapper around ACPI_BUFFER to handle memory ownership and allow easy iteration.
#ifndef SRC_DEVICES_BOARD_LIB_ACPI_UTIL_H_
#define SRC_DEVICES_BOARD_LIB_ACPI_UTIL_H_
#include <algorithm>
#include <memory>
#include <acpica/acpi.h>
namespace acpi {
namespace internal {
static inline uint32_t ExtractPnpIdWord(const ACPI_PNP_DEVICE_ID& id, size_t offset) {
auto buf = reinterpret_cast<const unsigned char*>(id.String);
auto buf_len = static_cast<size_t>(id.Length);
if (offset >= buf_len) {
return 0;
}
size_t i;
size_t avail = buf_len - offset;
uint32_t ret = buf[offset];
for (i = 1; i < std::min(avail, sizeof(uint32_t)); ++i) {
ret = (ret << 8) | buf[offset + i];
}
ret <<= (sizeof(uint32_t) - i) * 8;
return ret;
}
} // namespace internal
// AcpiBuffer provides RAII memory management for ACPI_BUFFERs as well as range
// based iterators for a specified ACPI_BUFFER type T.
template <class T>
class AcpiBuffer : public ACPI_BUFFER {
public:
AcpiBuffer() : ACPI_BUFFER{ACPI_ALLOCATE_BUFFER, nullptr} {}
AcpiBuffer(const AcpiBuffer&& acpi_buffer) noexcept : ACPI_BUFFER(std::move(acpi_buffer)) {}
AcpiBuffer(ACPI_SIZE length, void* pointer) : ACPI_BUFFER{length, pointer} {}
AcpiBuffer(const AcpiBuffer&) = delete;
~AcpiBuffer() { AcpiOsFree(Pointer); }
class iterator {
public:
explicit iterator(ACPI_BUFFER buffer)
: length_(buffer.Length), pointer_(static_cast<T*>(buffer.Pointer)) {}
iterator() : pointer_(nullptr) {}
T& operator*() { return *pointer_; }
friend bool operator==(const AcpiBuffer::iterator& ai, const AcpiBuffer::iterator& bi) {
return ai.pointer_ == bi.pointer_;
}
friend bool operator!=(const AcpiBuffer::iterator& ai, const AcpiBuffer::iterator& bi) {
return !(ai == bi);
}
iterator& operator++() {
length_ -= pointer_->Length;
pointer_ = reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(pointer_) + pointer_->Length);
// If we've reached ACPI's end of list node then return the end() sentinel
if (length_ == 0 || pointer_->Length == 0) {
pointer_ = nullptr;
}
return *this;
}
private:
ACPI_SIZE length_ = 0;
T* pointer_;
};
auto begin() const { return AcpiBuffer::iterator(*this); }
auto end() const { return AcpiBuffer::iterator(); }
};
// An RAII unique pointer type for resources allocated from the ACPICA library.
template <typename T>
struct UniquePtrDeleter {
void operator()(T* mem) { ACPI_FREE(mem); }
};
template <typename T>
using UniquePtr = std::unique_ptr<T, UniquePtrDeleter<T>>;
} // namespace acpi
#endif // SRC_DEVICES_BOARD_LIB_ACPI_UTIL_H_