aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/x300
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/x300')
-rw-r--r--host/lib/usrp/x300/CMakeLists.txt1
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp32
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp9
-rw-r--r--host/lib/usrp/x300/x300_mb_eeprom.cpp338
-rw-r--r--host/lib/usrp/x300/x300_mb_eeprom_iface.cpp190
-rw-r--r--host/lib/usrp/x300/x300_mb_eeprom_iface.hpp (renamed from host/lib/usrp/x300/x300_mb_eeprom.hpp)0
6 files changed, 388 insertions, 182 deletions
diff --git a/host/lib/usrp/x300/CMakeLists.txt b/host/lib/usrp/x300/CMakeLists.txt
index 5f8e83e1c..3a48c9900 100644
--- a/host/lib/usrp/x300/CMakeLists.txt
+++ b/host/lib/usrp/x300/CMakeLists.txt
@@ -34,6 +34,7 @@ IF(ENABLE_X300)
${CMAKE_CURRENT_SOURCE_DIR}/x300_dboard_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/x300_clock_ctrl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/x300_image_loader.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/x300_mb_eeprom_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/x300_mb_eeprom.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cdecode.c
)
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index 1e22f7fb7..f98bdb5b1 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -18,7 +18,7 @@
#include "x300_impl.hpp"
#include "x300_lvbitx.hpp"
#include "x310_lvbitx.hpp"
-#include "x300_mb_eeprom.hpp"
+#include "x300_mb_eeprom_iface.hpp"
#include "apply_corrections.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
@@ -125,7 +125,8 @@ static device_addrs_t x300_find_with_addr(const device_addr_t &hint)
i2c_core_100_wb32::sptr zpu_i2c = i2c_core_100_wb32::make(zpu_ctrl, I2C1_BASE);
x300_mb_eeprom_iface::sptr eeprom_iface = x300_mb_eeprom_iface::make(zpu_ctrl, zpu_i2c);
- const mboard_eeprom_t mb_eeprom(*eeprom_iface, "X300");
+ const mboard_eeprom_t mb_eeprom =
+ x300_impl::get_mb_eeprom(eeprom_iface);
if (mb_eeprom.size() == 0 or x300_impl::claim_status(zpu_ctrl) == x300_impl::CLAIMED_BY_OTHER)
{
// Skip device claimed by another process
@@ -233,7 +234,8 @@ static device_addrs_t x300_find_pcie(const device_addr_t &hint, bool explicit_qu
i2c_core_100_wb32::sptr zpu_i2c = i2c_core_100_wb32::make(zpu_ctrl, I2C1_BASE);
x300_mb_eeprom_iface::sptr eeprom_iface = x300_mb_eeprom_iface::make(zpu_ctrl, zpu_i2c);
- const mboard_eeprom_t mb_eeprom(*eeprom_iface, "X300");
+ const mboard_eeprom_t mb_eeprom =
+ x300_impl::get_mb_eeprom(eeprom_iface);
if (mb_eeprom.size() == 0 or x300_impl::claim_status(zpu_ctrl) == x300_impl::CLAIMED_BY_OTHER)
{
// Skip device claimed by another process
@@ -783,13 +785,21 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
x300_mb_eeprom_iface::sptr eeprom16 = x300_mb_eeprom_iface::make(mb.zpu_ctrl, mb.zpu_i2c);
if (dev_addr.has_key("blank_eeprom"))
{
- UHD_LOGGER_WARNING("X300") << "Obliterating the motherboard EEPROM..." ;
+ UHD_LOGGER_WARNING("X300") << "Obliterating the motherboard EEPROM...";
eeprom16->write_eeprom(0x50, 0, byte_vector_t(256, 0xff));
}
- const mboard_eeprom_t mb_eeprom(*eeprom16, "X300");
+
+ const mboard_eeprom_t mb_eeprom = get_mb_eeprom(eeprom16);
_tree->create<mboard_eeprom_t>(mb_path / "eeprom")
+ // Initialize the property with a current copy of the EEPROM contents
.set(mb_eeprom)
- .add_coerced_subscriber(boost::bind(&x300_impl::set_mb_eeprom, this, mb.zpu_i2c, _1));
+ // Whenever this property is written, update the chip
+ .add_coerced_subscriber(
+ [this, eeprom16](const mboard_eeprom_t &mb_eeprom){
+ this->set_mb_eeprom(eeprom16, mb_eeprom);
+ }
+ )
+ ;
bool recover_mb_eeprom = dev_addr.has_key("recover_mb_eeprom");
if (recover_mb_eeprom) {
@@ -1524,16 +1534,6 @@ bool x300_impl::is_pps_present(mboard_members_t& mb)
}
/***********************************************************************
- * eeprom
- **********************************************************************/
-
-void x300_impl::set_mb_eeprom(i2c_iface::sptr i2c, const mboard_eeprom_t &mb_eeprom)
-{
- i2c_iface::sptr eeprom16 = i2c->eeprom16();
- mb_eeprom.commit(*eeprom16, "X300");
-}
-
-/***********************************************************************
* claimer logic
**********************************************************************/
diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp
index 7186e5f4f..a1ff65a5c 100644
--- a/host/lib/usrp/x300/x300_impl.hpp
+++ b/host/lib/usrp/x300/x300_impl.hpp
@@ -147,6 +147,9 @@ public:
static x300_mboard_t get_mb_type_from_pcie(const std::string& resource, const std::string& rpc_port);
static x300_mboard_t get_mb_type_from_eeprom(const uhd::usrp::mboard_eeprom_t& mb_eeprom);
+ //! Read out the on-board EEPROM, convert to dict, and return
+ static uhd::usrp::mboard_eeprom_t get_mb_eeprom(uhd::i2c_iface::sptr i2c);
+
protected:
void subdev_to_blockid(
const uhd::usrp::subdev_spec_pair_t &spec, const size_t mb_i,
@@ -287,7 +290,11 @@ private:
bool wait_for_clk_locked(mboard_members_t& mb, uint32_t which, double timeout);
bool is_pps_present(mboard_members_t& mb);
- void set_mb_eeprom(uhd::i2c_iface::sptr i2c, const uhd::usrp::mboard_eeprom_t &);
+ //! Write the contents of an EEPROM dict to the on-board EEPROM
+ void set_mb_eeprom(
+ uhd::i2c_iface::sptr i2c,
+ const uhd::usrp::mboard_eeprom_t &
+ );
void check_fw_compat(const uhd::fs_path &mb_path, uhd::wb_iface::sptr iface);
void check_fpga_compat(const uhd::fs_path &mb_path, const mboard_members_t &members);
diff --git a/host/lib/usrp/x300/x300_mb_eeprom.cpp b/host/lib/usrp/x300/x300_mb_eeprom.cpp
index 084685991..da4cf6021 100644
--- a/host/lib/usrp/x300/x300_mb_eeprom.cpp
+++ b/host/lib/usrp/x300/x300_mb_eeprom.cpp
@@ -1,190 +1,198 @@
//
-// Copyright 2013-2016 Ettus Research LLC
+// Copyright 2017 Ettus Research (National Instruments Corp.)
//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
+// SPDX-License-Identifier: GPL-3.0
//
-/*
- * x300_mb_eeprom_iface
- * This interface was created to prevent MB EEPROM corruption while reading
- * data during discovery. For devices with firmware version newer than 5.0,
- * the EEPROM data is read into firmware memory and available without
- * claiming the device. For devices with firmware versions 5.0 and older,
- * the code makes sure to claim the device before driving the I2C bus. This
- * has the unfortunate side effect of preventing multiple processes from
- * discovering the device simultaneously, but is far better than having EEPROM
- * corruption.
- */
-
-#include "x300_mb_eeprom.hpp"
-#include "x300_fw_common.h"
-#include "x300_regs.hpp"
#include "x300_impl.hpp"
-#include <uhd/exception.hpp>
-#include <uhd/utils/platform.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <boost/thread.hpp>
+#include "eeprom_utils.hpp"
+#include <uhd/usrp/mboard_eeprom.hpp>
+#include <uhd/types/serial.hpp>
-using namespace uhd;
+namespace {
+ const uint8_t X300_EEPROM_ADDR = 0x50;
+
+ struct x300_eeprom_map
+ {
+ //identifying numbers
+ unsigned char revision[2];
+ unsigned char product[2];
+ unsigned char revision_compat[2];
+ uint8_t _pad0[2];
+
+ //all the mac addrs
+ uint8_t mac_addr0[6];
+ uint8_t _pad1[2];
+ uint8_t mac_addr1[6];
+ uint8_t _pad2[2];
+
+ //all the IP addrs
+ uint32_t gateway;
+ uint32_t subnet[4];
+ uint32_t ip_addr[4];
+ uint8_t _pad3[16];
+
+ //names and serials
+ unsigned char name[NAME_MAX_LEN];
+ unsigned char serial[SERIAL_LEN];
+ };
+}
-static const uint32_t X300_FW_SHMEM_IDENT_MIN_VERSION = 0x50001;
+using namespace uhd;
+using uhd::usrp::mboard_eeprom_t;
-class x300_mb_eeprom_iface_impl : public x300_mb_eeprom_iface
+mboard_eeprom_t x300_impl::get_mb_eeprom(uhd::i2c_iface::sptr iface)
{
-public:
+ byte_vector_t bytes =
+ iface->read_eeprom(X300_EEPROM_ADDR, 0, sizeof(struct x300_eeprom_map));
- x300_mb_eeprom_iface_impl(wb_iface::sptr wb, i2c_iface::sptr i2c) : _wb(wb), _i2c(i2c)
- {
- _compat_num = _wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_COMPAT_NUM));
+ mboard_eeprom_t mb_eeprom;
+ if (bytes.empty()) {
+ return mb_eeprom;
}
- ~x300_mb_eeprom_iface_impl()
+ //extract the revision number
+ mb_eeprom["revision"] = uint16_bytes_to_string(
+ byte_vector_t(
+ bytes.begin() + offsetof(x300_eeprom_map, revision),
+ bytes.begin() + (offsetof(x300_eeprom_map, revision)+2))
+ );
+
+ //extract the revision compat number
+ mb_eeprom["revision_compat"] = uint16_bytes_to_string(
+ byte_vector_t(
+ bytes.begin() + offsetof(x300_eeprom_map, revision_compat),
+ bytes.begin() + (offsetof(x300_eeprom_map, revision_compat)+2))
+ );
+
+ //extract the product code
+ mb_eeprom["product"] = uint16_bytes_to_string(
+ byte_vector_t(
+ bytes.begin() + offsetof(x300_eeprom_map, product),
+ bytes.begin() + (offsetof(x300_eeprom_map, product)+2))
+ );
+
+ //extract the mac addresses
+ mb_eeprom["mac-addr0"] = mac_addr_t::from_bytes(
+ byte_vector_t(
+ bytes.begin() + offsetof(x300_eeprom_map, mac_addr0),
+ bytes.begin() + (offsetof(x300_eeprom_map, mac_addr0)+6))
+ ).to_string();
+ mb_eeprom["mac-addr1"] = mac_addr_t::from_bytes(
+ byte_vector_t(
+ bytes.begin() + offsetof(x300_eeprom_map, mac_addr1),
+ bytes.begin() + (offsetof(x300_eeprom_map, mac_addr1)+6))
+ ).to_string();
+
+ //extract the ip addresses
+ boost::asio::ip::address_v4::bytes_type ip_addr_bytes;
+ byte_copy(
+ byte_vector_t(
+ bytes.begin() + offsetof(x300_eeprom_map, gateway),
+ bytes.begin() + (offsetof(x300_eeprom_map, gateway)+4)),
+ ip_addr_bytes
+ );
+ mb_eeprom["gateway"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();
+ for (size_t i = 0; i < 4; i++)
{
- /* NOP */
+ const std::string n(1, i+'0');
+ byte_copy(
+ byte_vector_t(
+ bytes.begin() + (offsetof(x300_eeprom_map, ip_addr)+(i*4)),
+ bytes.begin() + (offsetof(x300_eeprom_map, ip_addr)+(i*4)+4)),
+ ip_addr_bytes
+ );
+ mb_eeprom["ip-addr"+n] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();
+
+ byte_copy(
+ byte_vector_t(
+ bytes.begin() + (offsetof(x300_eeprom_map, subnet)+(i*4)),
+ bytes.begin() + (offsetof(x300_eeprom_map, subnet)+(i*4)+4)),
+ ip_addr_bytes
+ );
+ mb_eeprom["subnet"+n] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();
}
- /*!
- * Write bytes over the i2c.
- * \param addr the address
- * \param buf the vector of bytes
- */
- void write_i2c(
- uint16_t addr,
- const byte_vector_t &buf
- )
- {
- UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR);
- if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US)
- {
- throw uhd::io_error("Attempted to write MB EEPROM without claim to device.");
- }
- _i2c->write_i2c(addr, buf);
- }
+ //extract the serial
+ mb_eeprom["serial"] = bytes_to_string(
+ byte_vector_t(
+ bytes.begin() + offsetof(x300_eeprom_map, serial),
+ bytes.begin() + (offsetof(x300_eeprom_map, serial)+SERIAL_LEN))
+ );
+
+ //extract the name
+ mb_eeprom["name"] = bytes_to_string(
+ byte_vector_t(
+ bytes.begin() + offsetof(x300_eeprom_map, name),
+ bytes.begin() + (offsetof(x300_eeprom_map, name)+NAME_MAX_LEN))
+ );
+
+ return mb_eeprom;
+}
- /*!
- * Read bytes over the i2c.
- * \param addr the address
- * \param num_bytes number of bytes to read
- * \return a vector of bytes
- */
- byte_vector_t read_i2c(
- uint16_t addr,
- size_t num_bytes
- )
- {
- UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR);
- byte_vector_t bytes;
- if (_compat_num > X300_FW_SHMEM_IDENT_MIN_VERSION)
- {
- bytes = read_eeprom(addr, 0, num_bytes);
- } else {
- x300_impl::claim_status_t status = x300_impl::claim_status(_wb);
- // Claim device before driving the I2C bus
- if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb))
- {
- bytes = _i2c->read_i2c(addr, num_bytes);
- if (status != x300_impl::CLAIMED_BY_US)
- {
- // We didn't originally have the claim, so give it up
- x300_impl::release(_wb);
- }
- }
- }
- return bytes;
- }
- /*!
- * Write bytes to an eeprom.
- * \param addr the address
- * \param offset byte offset
- * \param buf the vector of bytes
- */
- void write_eeprom(
- uint16_t addr,
- uint16_t offset,
- const byte_vector_t &buf
- )
+void x300_impl::set_mb_eeprom(
+ i2c_iface::sptr iface,
+ const mboard_eeprom_t &mb_eeprom
+) {
+ //parse the revision number
+ if (mb_eeprom.has_key("revision")) iface->write_eeprom(
+ X300_EEPROM_ADDR, offsetof(x300_eeprom_map, revision),
+ string_to_uint16_bytes(mb_eeprom["revision"])
+ );
+
+ //parse the revision compat number
+ if (mb_eeprom.has_key("revision_compat")) iface->write_eeprom(
+ X300_EEPROM_ADDR, offsetof(x300_eeprom_map, revision_compat),
+ string_to_uint16_bytes(mb_eeprom["revision_compat"])
+ );
+
+ //parse the product code
+ if (mb_eeprom.has_key("product")) iface->write_eeprom(
+ X300_EEPROM_ADDR, offsetof(x300_eeprom_map, product),
+ string_to_uint16_bytes(mb_eeprom["product"])
+ );
+
+ //store the mac addresses
+ if (mb_eeprom.has_key("mac-addr0")) iface->write_eeprom(
+ X300_EEPROM_ADDR, offsetof(x300_eeprom_map, mac_addr0),
+ mac_addr_t::from_string(mb_eeprom["mac-addr0"]).to_bytes()
+ );
+ if (mb_eeprom.has_key("mac-addr1")) iface->write_eeprom(
+ X300_EEPROM_ADDR, offsetof(x300_eeprom_map, mac_addr1),
+ mac_addr_t::from_string(mb_eeprom["mac-addr1"]).to_bytes()
+ );
+
+ //store the ip addresses
+ byte_vector_t ip_addr_bytes(4);
+ if (mb_eeprom.has_key("gateway")){
+ byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["gateway"]).to_bytes(), ip_addr_bytes);
+ iface->write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, gateway), ip_addr_bytes);
+ }
+ for (size_t i = 0; i < 4; i++)
{
- UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR);
- if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US)
- {
- throw uhd::io_error("Attempted to write MB EEPROM without claim to device.");
+ const std::string n(1, i+'0');
+ if (mb_eeprom.has_key("ip-addr"+n)){
+ byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"+n]).to_bytes(), ip_addr_bytes);
+ iface->write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, ip_addr)+(i*4), ip_addr_bytes);
}
- _i2c->write_eeprom(addr, offset, buf);
- }
- /*!
- * Read bytes from an eeprom.
- * \param addr the address
- * \param offset byte offset
- * \param num_bytes number of bytes to read
- * \return a vector of bytes
- */
- byte_vector_t read_eeprom(
- uint16_t addr,
- uint16_t offset,
- size_t num_bytes
- )
- {
- UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR);
- byte_vector_t bytes;
- x300_impl::claim_status_t status = x300_impl::claim_status(_wb);
- if (_compat_num >= X300_FW_SHMEM_IDENT_MIN_VERSION)
- {
- // Get MB EEPROM data from firmware memory
- if (num_bytes == 0) return bytes;
-
- size_t bytes_read = 0;
- for (size_t word = offset / 4; bytes_read < num_bytes; word++)
- {
- uint32_t value = byteswap(_wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_IDENT + word)));
- for (size_t byte = offset % 4; byte < 4 and bytes_read < num_bytes; byte++)
- {
- bytes.push_back(uint8_t((value >> (byte * 8)) & 0xff));
- bytes_read++;
- }
- }
- } else {
- // Claim device before driving the I2C bus
- if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb))
- {
- bytes = _i2c->read_eeprom(addr, offset, num_bytes);
- if (status != x300_impl::CLAIMED_BY_US)
- {
- // We didn't originally have the claim, so give it up
- x300_impl::release(_wb);
- }
- }
+ if (mb_eeprom.has_key("subnet"+n)){
+ byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["subnet"+n]).to_bytes(), ip_addr_bytes);
+ iface->write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, subnet)+(i*4), ip_addr_bytes);
}
- return bytes;
}
-
-private:
- wb_iface::sptr _wb;
- i2c_iface::sptr _i2c;
- uint32_t _compat_num;
-};
-
-x300_mb_eeprom_iface::~x300_mb_eeprom_iface(void)
-{
- /* NOP */
-}
-
-x300_mb_eeprom_iface::sptr x300_mb_eeprom_iface::make(wb_iface::sptr wb, i2c_iface::sptr i2c)
-{
- return boost::make_shared<x300_mb_eeprom_iface_impl>(wb, i2c->eeprom16());
+ //store the serial
+ if (mb_eeprom.has_key("serial")) iface->write_eeprom(
+ X300_EEPROM_ADDR, offsetof(x300_eeprom_map, serial),
+ string_to_bytes(mb_eeprom["serial"], SERIAL_LEN)
+ );
+
+ //store the name
+ if (mb_eeprom.has_key("name")) iface->write_eeprom(
+ X300_EEPROM_ADDR, offsetof(x300_eeprom_map, name),
+ string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN)
+ );
}
diff --git a/host/lib/usrp/x300/x300_mb_eeprom_iface.cpp b/host/lib/usrp/x300/x300_mb_eeprom_iface.cpp
new file mode 100644
index 000000000..adc766c39
--- /dev/null
+++ b/host/lib/usrp/x300/x300_mb_eeprom_iface.cpp
@@ -0,0 +1,190 @@
+//
+// Copyright 2013-2016 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+/*
+ * x300_mb_eeprom_iface
+ * This interface was created to prevent MB EEPROM corruption while reading
+ * data during discovery. For devices with firmware version newer than 5.0,
+ * the EEPROM data is read into firmware memory and available without
+ * claiming the device. For devices with firmware versions 5.0 and older,
+ * the code makes sure to claim the device before driving the I2C bus. This
+ * has the unfortunate side effect of preventing multiple processes from
+ * discovering the device simultaneously, but is far better than having EEPROM
+ * corruption.
+ */
+
+#include "x300_mb_eeprom_iface.hpp"
+#include "x300_fw_common.h"
+#include "x300_regs.hpp"
+#include "x300_impl.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/platform.hpp>
+#include <uhd/utils/log.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <boost/thread.hpp>
+
+using namespace uhd;
+
+static const uint32_t X300_FW_SHMEM_IDENT_MIN_VERSION = 0x50001;
+
+class x300_mb_eeprom_iface_impl : public x300_mb_eeprom_iface
+{
+public:
+
+ x300_mb_eeprom_iface_impl(wb_iface::sptr wb, i2c_iface::sptr i2c) : _wb(wb), _i2c(i2c)
+ {
+ _compat_num = _wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_COMPAT_NUM));
+ }
+
+ ~x300_mb_eeprom_iface_impl()
+ {
+ /* NOP */
+ }
+
+ /*!
+ * Write bytes over the i2c.
+ * \param addr the address
+ * \param buf the vector of bytes
+ */
+ void write_i2c(
+ uint16_t addr,
+ const byte_vector_t &buf
+ )
+ {
+ UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR);
+ if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US)
+ {
+ throw uhd::io_error("Attempted to write MB EEPROM without claim to device.");
+ }
+ _i2c->write_i2c(addr, buf);
+ }
+
+ /*!
+ * Read bytes over the i2c.
+ * \param addr the address
+ * \param num_bytes number of bytes to read
+ * \return a vector of bytes
+ */
+ byte_vector_t read_i2c(
+ uint16_t addr,
+ size_t num_bytes
+ )
+ {
+ UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR);
+ byte_vector_t bytes;
+ if (_compat_num > X300_FW_SHMEM_IDENT_MIN_VERSION)
+ {
+ bytes = read_eeprom(addr, 0, num_bytes);
+ } else {
+ x300_impl::claim_status_t status = x300_impl::claim_status(_wb);
+ // Claim device before driving the I2C bus
+ if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb))
+ {
+ bytes = _i2c->read_i2c(addr, num_bytes);
+ if (status != x300_impl::CLAIMED_BY_US)
+ {
+ // We didn't originally have the claim, so give it up
+ x300_impl::release(_wb);
+ }
+ }
+ }
+ return bytes;
+ }
+
+ /*!
+ * Write bytes to an eeprom.
+ * \param addr the address
+ * \param offset byte offset
+ * \param buf the vector of bytes
+ */
+ void write_eeprom(
+ uint16_t addr,
+ uint16_t offset,
+ const byte_vector_t &buf
+ )
+ {
+ UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR);
+ if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US)
+ {
+ throw uhd::io_error("Attempted to write MB EEPROM without claim to device.");
+ }
+ _i2c->write_eeprom(addr, offset, buf);
+ }
+
+ /*!
+ * Read bytes from an eeprom.
+ * \param addr the address
+ * \param offset byte offset
+ * \param num_bytes number of bytes to read
+ * \return a vector of bytes
+ */
+ byte_vector_t read_eeprom(
+ uint16_t addr,
+ uint16_t offset,
+ size_t num_bytes
+ )
+ {
+ UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR);
+ byte_vector_t bytes;
+ x300_impl::claim_status_t status = x300_impl::claim_status(_wb);
+ if (_compat_num >= X300_FW_SHMEM_IDENT_MIN_VERSION)
+ {
+ // Get MB EEPROM data from firmware memory
+ if (num_bytes == 0) return bytes;
+
+ size_t bytes_read = 0;
+ for (size_t word = offset / 4; bytes_read < num_bytes; word++)
+ {
+ uint32_t value = byteswap(_wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_IDENT + word)));
+ for (size_t byte = offset % 4; byte < 4 and bytes_read < num_bytes; byte++)
+ {
+ bytes.push_back(uint8_t((value >> (byte * 8)) & 0xff));
+ bytes_read++;
+ }
+ }
+ } else {
+ // Claim device before driving the I2C bus
+ if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb))
+ {
+ bytes = _i2c->read_eeprom(addr, offset, num_bytes);
+ if (status != x300_impl::CLAIMED_BY_US)
+ {
+ // We didn't originally have the claim, so give it up
+ x300_impl::release(_wb);
+ }
+ }
+ }
+ return bytes;
+ }
+
+
+private:
+ wb_iface::sptr _wb;
+ i2c_iface::sptr _i2c;
+ uint32_t _compat_num;
+};
+
+x300_mb_eeprom_iface::~x300_mb_eeprom_iface(void)
+{
+ /* NOP */
+}
+
+x300_mb_eeprom_iface::sptr x300_mb_eeprom_iface::make(wb_iface::sptr wb, i2c_iface::sptr i2c)
+{
+ return boost::make_shared<x300_mb_eeprom_iface_impl>(wb, i2c->eeprom16());
+}
+
diff --git a/host/lib/usrp/x300/x300_mb_eeprom.hpp b/host/lib/usrp/x300/x300_mb_eeprom_iface.hpp
index 0649855c6..0649855c6 100644
--- a/host/lib/usrp/x300/x300_mb_eeprom.hpp
+++ b/host/lib/usrp/x300/x300_mb_eeprom_iface.hpp