feat: port MT76 firmware load and download script
Add chip::load_firmware(): validates the xow_dongle.bin header, DMAs the ILM and DLM images in 0x3800-byte chunks over EP 0x04 OUT with FCE completion polling, then loads the IVB and waits for the firmware to start. Probe now issues a USB reset first (port of usb_reset_device), matching xone_dongle_probe. The chip keeps its firmware across a USB reset on macOS and does not set the upstream reset-complete bit, so load_firmware falls back to the running firmware when the chip is still alive. Verified on hardware: fresh load and re-plug both return success. Add scripts/download-firmware.sh (port of install/firmware.sh), which fetches the driver CAB from Windows Update and extracts firmware/xow_dongle.bin, hash-verified. Co-Authored-By: qwen3.8-27b@q2_k_xl: ported firmware load and download script
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ if(NOT CMAKE_GENERATOR MATCHES "^(Ninja|Xcode)$")
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.21)
|
cmake_minimum_required(VERSION 3.21)
|
||||||
project(xone_macos VERSION 0.1.5 LANGUAGES CXX Swift)
|
project(xone_macos VERSION 0.1.6 LANGUAGES CXX Swift)
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,23 @@ public:
|
|||||||
// MAC address from EFUSE with the 62:45:bd fallback applied.
|
// MAC address from EFUSE with the 62:45:bd fallback applied.
|
||||||
auto mac_address() -> std::array<std::uint8_t, 6>;
|
auto mac_address() -> std::array<std::uint8_t, 6>;
|
||||||
|
|
||||||
|
// Load the firmware image from a file (port of xone_mt76_load_firmware).
|
||||||
|
// Resets the MCU if firmware is already loaded. Returns 0 or -errno.
|
||||||
|
auto load_firmware(char const *path) -> int;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Send an MCU command (port of xone_mt76_send_command). `cmd` is the
|
||||||
|
// MT_MCU_MSG_CMD_TYPE field. Returns bytes written, or a negative errno.
|
||||||
|
auto send_command(std::uint32_t cmd, void const *payload,
|
||||||
|
std::size_t payload_len) -> int;
|
||||||
|
|
||||||
|
// Firmware load steps (port of xone_mt76_*).
|
||||||
|
auto load_ivb() -> int;
|
||||||
|
auto send_firmware_part(std::uint32_t offset, void const *data,
|
||||||
|
std::size_t len) -> int;
|
||||||
|
auto send_firmware(void const *fw_data, std::size_t fw_size) -> int;
|
||||||
|
auto reset_firmware() -> int;
|
||||||
|
|
||||||
usb::transport &transport_;
|
usb::transport &transport_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,11 @@
|
|||||||
// init and firmware load increments.
|
// init and firmware load increments.
|
||||||
// ==============================================================================
|
// ==============================================================================
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "common/types.hpp"
|
||||||
|
|
||||||
namespace xone::mt76 {
|
namespace xone::mt76 {
|
||||||
|
|
||||||
// Bitfield helpers (port of the kernel BIT/GENMASK/FIELD_PREP macros).
|
// Bitfield helpers (port of the kernel BIT/GENMASK/FIELD_PREP macros).
|
||||||
@@ -54,4 +57,60 @@ enum efuse_mode : std::uint32_t {
|
|||||||
efuse_physical_read,
|
efuse_physical_read,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// MCU message header fields.
|
||||||
|
constexpr std::uint32_t mt_mcu_msg_len = genmask(15, 0);
|
||||||
|
constexpr std::uint32_t mt_mcu_msg_cmd_seq = genmask(19, 16);
|
||||||
|
constexpr std::uint32_t mt_mcu_msg_cmd_type = genmask(26, 20);
|
||||||
|
constexpr std::uint32_t mt_mcu_msg_port = genmask(29, 27);
|
||||||
|
constexpr std::uint32_t mt_mcu_msg_type = genmask(31, 30);
|
||||||
|
constexpr std::uint32_t mt_mcu_msg_type_cmd = bit(30);
|
||||||
|
|
||||||
|
// DMA message ports (MT_MCU_MSG_PORT field).
|
||||||
|
enum dma_msg_port : std::uint32_t {
|
||||||
|
wlan_port = 0,
|
||||||
|
cpu_rx_port,
|
||||||
|
cpu_tx_port,
|
||||||
|
host_port,
|
||||||
|
virtual_cpu_rx_port,
|
||||||
|
virtual_cpu_tx_port,
|
||||||
|
discard,
|
||||||
|
};
|
||||||
|
|
||||||
|
// MCU message header length (port of MT_CMD_HDR_LEN).
|
||||||
|
constexpr std::size_t cmd_hdr_len = 4;
|
||||||
|
|
||||||
|
// FCE DMA registers.
|
||||||
|
constexpr std::uint32_t mt_fce_dma_addr = 0x0230;
|
||||||
|
constexpr std::uint32_t mt_fce_dma_len = 0x0234;
|
||||||
|
|
||||||
|
// Firmware load registers and constants (port of XONE_MT_FW_*).
|
||||||
|
constexpr std::uint32_t xone_mt_rf_patch = 0x0130;
|
||||||
|
constexpr std::uint32_t fw_load_ivb = 0x12;
|
||||||
|
constexpr std::uint32_t fw_ilm_offset = 0x080000;
|
||||||
|
constexpr std::uint32_t fw_dlm_offset = 0x110800;
|
||||||
|
constexpr std::size_t fw_chunk_size = 0x3800;
|
||||||
|
|
||||||
|
// USB DMA control register and bits.
|
||||||
|
constexpr std::uint32_t mt_usb_u3dma_cfg = 0x9018;
|
||||||
|
constexpr std::uint32_t mt_usb_dma_cfg_rx_bulk_en = bit(22);
|
||||||
|
constexpr std::uint32_t mt_usb_dma_cfg_tx_bulk_en = bit(23);
|
||||||
|
|
||||||
|
// Firmware load configuration registers.
|
||||||
|
constexpr std::uint32_t mt_fce_pse_ctrl = 0x0800;
|
||||||
|
constexpr std::uint32_t mt_tx_cpu_from_fce_base_ptr = 0x09a0;
|
||||||
|
constexpr std::uint32_t mt_tx_cpu_from_fce_max_count = 0x09a4;
|
||||||
|
constexpr std::uint32_t mt_tx_cpu_from_fce_cpu_desc_idx = 0x09a8;
|
||||||
|
constexpr std::uint32_t mt_fce_pdma_global_conf = 0x09c4;
|
||||||
|
constexpr std::uint32_t mt_fce_skip_fs = 0x0a6c;
|
||||||
|
|
||||||
|
// Firmware file header (port of struct mt76_fw_header).
|
||||||
|
struct fw_header {
|
||||||
|
std::uint32_t ilm_len; // little-endian on disk
|
||||||
|
std::uint32_t dlm_len; // little-endian on disk
|
||||||
|
std::uint16_t build_ver;
|
||||||
|
std::uint16_t fw_ver;
|
||||||
|
std::uint8_t pad[4];
|
||||||
|
char build_time[16];
|
||||||
|
} XONE_PACKED;
|
||||||
|
|
||||||
} // namespace xone::mt76
|
} // namespace xone::mt76
|
||||||
|
|||||||
Executable
+48
@@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Download and extract the wireless dongle firmware from Windows Update.
|
||||||
|
# Port of install/firmware.sh from medusalix/xone.
|
||||||
|
#
|
||||||
|
# The firmware is subject to Microsoft's Terms of Use:
|
||||||
|
# https://www.microsoft.com/en-us/legal/terms-of-use
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
firmware_url='http://download.windowsupdate.com/c/msdownload/update/driver/drvs/2017/07/1cd6a87c-623f-4407-a52d-c31be49e925c_e19f60808bdcbfbd3c3df6be3e71ffc52e43261e.cab'
|
||||||
|
firmware_hash='48084d9fa53b9bb04358f3bb127b7495dc8f7bb0b3ca1437bd24ef2b6eabdf66'
|
||||||
|
|
||||||
|
echo "The firmware for the wireless dongle is subject to Microsoft's Terms of Use:"
|
||||||
|
echo 'https://www.microsoft.com/en-us/legal/terms-of-use'
|
||||||
|
echo
|
||||||
|
echo 'Press enter to continue!'
|
||||||
|
read -r _
|
||||||
|
|
||||||
|
command -v curl >/dev/null 2>&1 || { echo 'This script requires curl!' >&2; exit 1; }
|
||||||
|
|
||||||
|
sha256() {
|
||||||
|
if command -v sha256sum >/dev/null 2>&1; then
|
||||||
|
sha256sum "$1" | cut -d' ' -f1
|
||||||
|
else
|
||||||
|
shasum -a 256 "$1" | cut -d' ' -f1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpdir=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$tmpdir"' EXIT INT HUP TERM
|
||||||
|
|
||||||
|
echo "Downloading driver package..."
|
||||||
|
curl -L --fail -o "$tmpdir/driver.cab" "$firmware_url"
|
||||||
|
|
||||||
|
# Extract the firmware image (requires a libarchive-based tar, e.g. macOS).
|
||||||
|
tar -xf "$tmpdir/driver.cab" -C "$tmpdir"
|
||||||
|
|
||||||
|
actual=$(sha256 "$tmpdir/FW_ACC_00U.bin")
|
||||||
|
if [ "$actual" != "$firmware_hash" ]; then
|
||||||
|
echo "Firmware hash mismatch: $actual" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p firmware
|
||||||
|
mv "$tmpdir/FW_ACC_00U.bin" firmware/xow_dongle.bin
|
||||||
|
echo "Firmware written to firmware/xow_dongle.bin"
|
||||||
@@ -6,6 +6,9 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@@ -19,6 +22,39 @@ namespace xone::mt76 {
|
|||||||
// Poll retry count (port of XONE_MT_POLL_RETRIES).
|
// Poll retry count (port of XONE_MT_POLL_RETRIES).
|
||||||
constexpr int poll_retries = 50;
|
constexpr int poll_retries = 50;
|
||||||
|
|
||||||
|
// Build a command message (port of xone_mt76_prep_message):
|
||||||
|
// [u32 header][payload rounded up to u32][zero pad + 4-byte trailer]
|
||||||
|
auto build_message(std::uint32_t info, void const *payload,
|
||||||
|
std::size_t payload_len) -> std::vector<std::uint8_t>
|
||||||
|
{
|
||||||
|
auto rounded = (payload_len + 3) & ~std::size_t{3};
|
||||||
|
auto buf = std::vector<std::uint8_t>(rounded + 2 * cmd_hdr_len, 0);
|
||||||
|
xone::store_le32(buf.data(), info | field_prep(mt_mcu_msg_len, rounded));
|
||||||
|
if (payload_len > 0)
|
||||||
|
std::memcpy(buf.data() + cmd_hdr_len, payload, payload_len);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a firmware file into memory (port of request_firmware).
|
||||||
|
auto read_firmware_file(char const *path) -> std::optional<std::vector<std::uint8_t>>
|
||||||
|
{
|
||||||
|
std::ifstream in(path, std::ios::binary | std::ios::ate);
|
||||||
|
if (!in)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
auto size = in.tellg();
|
||||||
|
if (size <= 0)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
in.seekg(0);
|
||||||
|
std::vector<std::uint8_t> buf(static_cast<std::size_t>(size));
|
||||||
|
if (!in.read(reinterpret_cast<char *>(buf.data()), size))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
chip::chip(usb::transport &transport) : transport_(transport) {}
|
chip::chip(usb::transport &transport) : transport_(transport) {}
|
||||||
|
|
||||||
auto chip::read_register(std::uint32_t addr) -> std::uint32_t
|
auto chip::read_register(std::uint32_t addr) -> std::uint32_t
|
||||||
@@ -122,4 +158,138 @@ auto chip::mac_address() -> std::array<std::uint8_t, 6>
|
|||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto chip::send_command(std::uint32_t cmd, void const *payload,
|
||||||
|
std::size_t payload_len) -> int
|
||||||
|
{
|
||||||
|
auto info = mt_mcu_msg_type_cmd
|
||||||
|
| field_prep(mt_mcu_msg_port, dma_msg_port::cpu_tx_port)
|
||||||
|
| field_prep(mt_mcu_msg_cmd_type, cmd);
|
||||||
|
|
||||||
|
auto buf = build_message(info, payload, payload_len);
|
||||||
|
return transport_.bulk_write(buf.data(), buf.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto chip::load_ivb() -> int
|
||||||
|
{
|
||||||
|
return transport_.send_vendor_request(usb::vendor_request::dev_mode, false,
|
||||||
|
static_cast<std::uint16_t>(fw_load_ivb), 0,
|
||||||
|
nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto chip::send_firmware_part(std::uint32_t offset, void const *data,
|
||||||
|
std::size_t len) -> int
|
||||||
|
{
|
||||||
|
for (std::size_t pos = 0; pos < len; pos += fw_chunk_size) {
|
||||||
|
auto chunk_len = std::min(len - pos, fw_chunk_size);
|
||||||
|
auto rounded = (chunk_len + 3) & ~std::size_t{3};
|
||||||
|
|
||||||
|
write_register(mt_fce_dma_addr | mt_vend_type_cfg, offset + pos);
|
||||||
|
write_register(mt_fce_dma_len | mt_vend_type_cfg,
|
||||||
|
static_cast<std::uint32_t>(rounded) << 16);
|
||||||
|
|
||||||
|
if (auto ret = send_command(0,
|
||||||
|
static_cast<std::uint8_t const *>(data) + pos,
|
||||||
|
chunk_len);
|
||||||
|
ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
auto complete = 0xc0000000u | (static_cast<std::uint32_t>(rounded) << 16);
|
||||||
|
if (!poll(mt_fce_dma_len | mt_vend_type_cfg, 0xFFFFFFFFu, complete))
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto chip::send_firmware(void const *fw_data, std::size_t fw_size) -> int
|
||||||
|
{
|
||||||
|
if (fw_size < sizeof(fw_header))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
auto header = static_cast<fw_header const *>(fw_data);
|
||||||
|
auto ilm_len = xone::load_le32(&header->ilm_len);
|
||||||
|
auto dlm_len = xone::load_le32(&header->dlm_len);
|
||||||
|
if (fw_size != sizeof(fw_header) + ilm_len + dlm_len)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
char build_time[17] = {};
|
||||||
|
std::memcpy(build_time, header->build_time, sizeof(header->build_time));
|
||||||
|
xone::log_msg(log_level::info, "mt76: firmware build %s", build_time);
|
||||||
|
|
||||||
|
// Configure the DMA, enable FCE and packet DMA.
|
||||||
|
write_register(mt_usb_u3dma_cfg | mt_vend_type_cfg,
|
||||||
|
mt_usb_dma_cfg_tx_bulk_en | mt_usb_dma_cfg_rx_bulk_en);
|
||||||
|
write_register(mt_fce_pse_ctrl, 0x01);
|
||||||
|
write_register(mt_tx_cpu_from_fce_base_ptr, 0x00400230);
|
||||||
|
write_register(mt_tx_cpu_from_fce_max_count, 0x01);
|
||||||
|
write_register(mt_tx_cpu_from_fce_cpu_desc_idx, 0x01);
|
||||||
|
write_register(mt_fce_pdma_global_conf, 0x44);
|
||||||
|
write_register(mt_fce_skip_fs, 0x03);
|
||||||
|
|
||||||
|
auto base = static_cast<std::uint8_t const *>(fw_data) + sizeof(fw_header);
|
||||||
|
if (auto ret = send_firmware_part(fw_ilm_offset, base, ilm_len); ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return send_firmware_part(fw_dlm_offset, base + ilm_len, dlm_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto chip::reset_firmware() -> int
|
||||||
|
{
|
||||||
|
// Apply power-on RF patch.
|
||||||
|
auto val = read_register(xone_mt_rf_patch | mt_vend_type_cfg);
|
||||||
|
write_register(xone_mt_rf_patch | mt_vend_type_cfg, val & ~bit(19));
|
||||||
|
|
||||||
|
if (auto err = load_ivb(); err != 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// Wait for the reset.
|
||||||
|
if (!poll(mt_fce_dma_addr | mt_vend_type_cfg, 0x80000000u, 0x80000000u))
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto chip::load_firmware(char const *path) -> int
|
||||||
|
{
|
||||||
|
// If firmware is already loaded, reset the MCU.
|
||||||
|
if (read_register(mt_fce_dma_addr | mt_vend_type_cfg)) {
|
||||||
|
int err = reset_firmware();
|
||||||
|
if (err == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// The chip keeps its firmware across a USB reset and does not set
|
||||||
|
// the reset-complete bit on this hardware. If it is still alive
|
||||||
|
// with the firmware running, use the running firmware as-is.
|
||||||
|
std::uint8_t id[4] = {};
|
||||||
|
if (read_register(mt_fce_dma_addr | mt_vend_type_cfg) & 0x01u &&
|
||||||
|
read_efuse(mt_ee_chip_id, id, sizeof(id)) == 0) {
|
||||||
|
xone::log_msg(log_level::warn,
|
||||||
|
"mt76: firmware reset incomplete; using running firmware");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fw = read_firmware_file(path);
|
||||||
|
if (!fw.has_value()) {
|
||||||
|
xone::log_msg(log_level::error, "mt76: firmware not found: %s", path);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = send_firmware(fw->data(), fw->size());
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
write_register(mt_fce_dma_addr | mt_vend_type_cfg, 0);
|
||||||
|
if (auto err = load_ivb(); err != 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// Wait for the firmware to start.
|
||||||
|
if (!poll(mt_fce_dma_addr | mt_vend_type_cfg, 0x01u, 0x01u))
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xone::mt76
|
} // namespace xone::mt76
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ struct transport::state {
|
|||||||
// struct, and methods are called as (*ref)->Method(ref, ...).
|
// struct, and methods are called as (*ref)->Method(ref, ...).
|
||||||
io_service_t service = 0;
|
io_service_t service = 0;
|
||||||
IOCFPlugInInterface **dev_iodev = nullptr;
|
IOCFPlugInInterface **dev_iodev = nullptr;
|
||||||
IOUSBDeviceInterface197 **dev_ref = nullptr;
|
// Version 500 interface: adds ResetDevice (port of usb_reset_device).
|
||||||
|
IOUSBDeviceInterface500 **dev_ref = nullptr;
|
||||||
bool dev_opened = false;
|
bool dev_opened = false;
|
||||||
|
|
||||||
struct iface_conn {
|
struct iface_conn {
|
||||||
@@ -232,12 +233,12 @@ auto transport::open(frame_callback frames, disconnect_callback disconnected) ->
|
|||||||
|
|
||||||
void *slot = nullptr;
|
void *slot = nullptr;
|
||||||
HRESULT hr = (*state_->dev_iodev)->QueryInterface(state_->dev_iodev,
|
HRESULT hr = (*state_->dev_iodev)->QueryInterface(state_->dev_iodev,
|
||||||
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID197), &slot);
|
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID500), &slot);
|
||||||
if (hr != S_OK || !slot) {
|
if (hr != S_OK || !slot) {
|
||||||
xone::log_msg(log_level::error, "usb: query device interface failed");
|
xone::log_msg(log_level::error, "usb: query device interface failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
state_->dev_ref = static_cast<IOUSBDeviceInterface197 **>(slot);
|
state_->dev_ref = static_cast<IOUSBDeviceInterface500 **>(slot);
|
||||||
|
|
||||||
kr = (*state_->dev_ref)->USBDeviceOpen(state_->dev_ref);
|
kr = (*state_->dev_ref)->USBDeviceOpen(state_->dev_ref);
|
||||||
if (kr != kIOReturnSuccess) {
|
if (kr != kIOReturnSuccess) {
|
||||||
@@ -246,6 +247,14 @@ auto transport::open(frame_callback frames, disconnect_callback disconnected) ->
|
|||||||
}
|
}
|
||||||
state_->dev_opened = true;
|
state_->dev_opened = true;
|
||||||
|
|
||||||
|
// Reset the chip so it starts from the boot ROM (port of the
|
||||||
|
// usb_reset_device call in xone_dongle_probe).
|
||||||
|
kr = (*state_->dev_ref)->ResetDevice(state_->dev_ref);
|
||||||
|
if (kr != kIOReturnSuccess) {
|
||||||
|
xone::log_msg(log_level::error, "usb: reset device failed (%d)", kr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Open every interface and collect the endpoint pipes we need.
|
// Open every interface and collect the endpoint pipes we need.
|
||||||
io_iterator_t children = 0;
|
io_iterator_t children = 0;
|
||||||
kr = IORegistryEntryGetChildIterator(state_->service, kIOServicePlane, &children);
|
kr = IORegistryEntryGetChildIterator(state_->service, kIOServicePlane, &children);
|
||||||
|
|||||||
@@ -32,10 +32,22 @@ void test_efuse_registers(void)
|
|||||||
TEST_ASSERT_EQUAL_UINT32(xone::mt76::mt_vend_type_cfg, 0x40000000u);
|
TEST_ASSERT_EQUAL_UINT32(xone::mt76::mt_vend_type_cfg, 0x40000000u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pin the firmware load layout to transport/mt76.c values.
|
||||||
|
void test_firmware_layout(void)
|
||||||
|
{
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(xone::mt76::fw_ilm_offset, 0x080000);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(xone::mt76::fw_dlm_offset, 0x110800);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(xone::mt76::fw_chunk_size, 0x3800);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(sizeof(xone::mt76::fw_header), 32);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(xone::mt76::mt_fce_dma_addr, 0x0230);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(xone::mt76::mt_fce_dma_len, 0x0234);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
UNITY_BEGIN();
|
UNITY_BEGIN();
|
||||||
RUN_TEST(test_bitfield_helpers);
|
RUN_TEST(test_bitfield_helpers);
|
||||||
RUN_TEST(test_efuse_registers);
|
RUN_TEST(test_efuse_registers);
|
||||||
|
RUN_TEST(test_firmware_layout);
|
||||||
return UNITY_END();
|
return UNITY_END();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user