From 0e0c610df0d3d4044d0b21ddc1752a5dacd7f86e Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Tue, 4 Feb 2014 00:18:51 +0100 Subject: utils/regtools: make qeditor able to poke directly at a hwstub device This commit add the very handy feature of being able to read registers directly from a device using hwstub. This is mostly trivial using the hwstub library and the biggest change here is actually: - being able to read registers by name and/or addresses - being able to enumerate devives The UI code currently doesn't handle hotplug but the backend does so it should be trivial to add in the future. It also opens up the possibility the write registers from hwstub or save the register values to a file. Since it relies on both hwstub and libusb, a switch has been introduced in qmake to disable it (use -config nohwstub). Change-Id: I5d7d7a2a7c97ecd7407227357c8553c2773ea6cc --- utils/regtools/qeditor/backend.cpp | 317 +++++++++++++++++++++++++++++++++---- 1 file changed, 290 insertions(+), 27 deletions(-) (limited to 'utils/regtools/qeditor/backend.cpp') diff --git a/utils/regtools/qeditor/backend.cpp b/utils/regtools/qeditor/backend.cpp index e011965bd2..d2b75be701 100644 --- a/utils/regtools/qeditor/backend.cpp +++ b/utils/regtools/qeditor/backend.cpp @@ -3,6 +3,10 @@ #include #include "backend.h" +/** + * Backend + */ + Backend::Backend() { } @@ -43,9 +47,16 @@ IoBackend *Backend::CreateDummyIoBackend() return new DummyIoBackend(); } -IoBackend::IoBackend() +#ifdef HAVE_HWSTUB +IoBackend *Backend::CreateHWStubIoBackend(HWStubDevice *dev) { + return new HWStubIoBackend(dev); } +#endif + +/** + * FileIoBackend + */ FileIoBackend::FileIoBackend(const QString& filename) { @@ -91,27 +102,230 @@ bool FileIoBackend::Reload() return true; } -DummyIoBackend::DummyIoBackend() +#ifdef HAVE_HWSTUB +/** + * HWStubDevice + */ +HWStubDevice::HWStubDevice(struct libusb_device *dev) { + libusb_ref_device(dev); + m_dev = dev; + m_handle = 0; + m_hwdev = 0; + m_valid = Probe(); } -QString DummyIoBackend::GetSocName() +HWStubDevice::~HWStubDevice() { - return ""; + Close(); + libusb_unref_device(m_dev); } -bool DummyIoBackend::ReadRegister(const QString& name, soc_word_t& value) +int HWStubDevice::GetBusNumber() { - (void) name; - (void) value; + return libusb_get_bus_number(m_dev); +} + +int HWStubDevice::GetDevAddress() +{ + return libusb_get_device_address(m_dev); +} + +bool HWStubDevice::Probe() +{ + struct libusb_device_descriptor desc; + if(libusb_get_device_descriptor(m_dev, &desc)) + return false; + if(desc.idVendor != HWSTUB_USB_VID || desc.idProduct != HWSTUB_USB_PID) + return false; + if(!Open()) + return false; + int ret = hwstub_get_desc(m_hwdev, HWSTUB_DT_VERSION, &m_hwdev_ver, sizeof(m_hwdev_ver)); + if(ret != sizeof(m_hwdev_ver)) + goto Lerr; + if(m_hwdev_ver.bMajor != HWSTUB_VERSION_MAJOR || m_hwdev_ver.bMinor < HWSTUB_VERSION_MINOR) + goto Lerr; + // get target + ret = hwstub_get_desc(m_hwdev, HWSTUB_DT_TARGET, &m_hwdev_target, sizeof(m_hwdev_target)); + if(ret != sizeof(m_hwdev_target)) + goto Lerr; + // get STMP information + if(m_hwdev_target.dID == HWSTUB_TARGET_STMP) + { + ret = hwstub_get_desc(m_hwdev, HWSTUB_DT_STMP, &m_hwdev_stmp, sizeof(m_hwdev_stmp)); + if(ret != sizeof(m_hwdev_stmp)) + goto Lerr; + } + Close(); + return true; + + Lerr: + Close(); return false; } -bool DummyIoBackend::Reload() +bool HWStubDevice::Open() +{ + if(libusb_open(m_dev, &m_handle)) + return false; + m_hwdev = hwstub_open(m_handle); + if(m_hwdev == 0) + { + libusb_close(m_handle); + return false; + } + return true; +} + +void HWStubDevice::Close() +{ + if(m_hwdev) + hwstub_release(m_hwdev); + m_hwdev = 0; + if(m_handle) + libusb_close(m_handle); + m_handle = 0; +} + +bool HWStubDevice::ReadMem(soc_addr_t addr, size_t length, void *buffer) +{ + if(!m_hwdev) + return false; + int ret = hwstub_rw_mem(m_hwdev, 1, addr, buffer, length); + return ret >= 0 && (size_t)ret == length; +} + +bool HWStubDevice::IsValid() +{ + return m_valid; +} + + +/** + * HWStubIoBackend + */ + +HWStubIoBackend::HWStubIoBackend(HWStubDevice *dev) +{ + m_dev = dev; + m_dev->Open(); + struct hwstub_target_desc_t target = m_dev->GetTargetInfo(); + if(target.dID == HWSTUB_TARGET_STMP) + { + struct hwstub_stmp_desc_t stmp = m_dev->GetSTMPInfo(); + if(stmp.wChipID == 0x3780) + m_soc = "imx233"; + else if(stmp.wChipID >= 0x3700 && stmp.wChipID < 0x3780) + m_soc = "stmp3700"; + else if(stmp.wChipID >= 0x3600 && stmp.wChipID < 0x3700) + m_soc = "stmp3600"; + else + m_soc = QString("stmp%1").arg(stmp.wChipID, 4, 16, QChar('0')); + } + else if(target.dID == HWSTUB_TARGET_RK27) + m_soc = "rk27x"; + else + m_soc = target.bName; +} + +QString HWStubIoBackend::GetSocName() +{ + return m_soc; +} + +HWStubIoBackend::~HWStubIoBackend() +{ + m_dev->Close(); +} + +bool HWStubIoBackend::ReadRegister(soc_addr_t addr, soc_word_t& value) +{ + return m_dev->ReadMem(addr, sizeof(value), &value); +} + +bool HWStubIoBackend::Reload() { return true; } +/** + * HWStubBackendHelper + */ +HWStubBackendHelper::HWStubBackendHelper() +{ + libusb_init(NULL); +#ifdef LIBUSB_NO_HOTPLUG + m_hotplug = false; +#else + m_hotplug = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG); + if(m_hotplug) + { + m_hotplug = LIBUSB_SUCCESS == libusb_hotplug_register_callback( + NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, + LIBUSB_HOTPLUG_ENUMERATE, HWSTUB_USB_VID, HWSTUB_USB_PID, HWSTUB_CLASS, + &HWStubBackendHelper::HotPlugCallback, reinterpret_cast< void* >(this), &m_hotplug_handle); + } +#endif +} + +HWStubBackendHelper::~HWStubBackendHelper() +{ +#ifndef LIBUSB_NO_HOTPLUG + if(m_hotplug) + libusb_hotplug_deregister_callback(NULL, m_hotplug_handle); +#endif +} + +QList< HWStubDevice* > HWStubBackendHelper::GetDevList() +{ + QList< HWStubDevice* > list; + libusb_device **dev_list; + ssize_t cnt = libusb_get_device_list(NULL, &dev_list); + for(int i = 0; i < cnt; i++) + { + HWStubDevice *dev = new HWStubDevice(dev_list[i]); + /* filter out non-hwstub devices */ + if(dev->IsValid()) + list.push_back(dev); + else + delete dev; + } + libusb_free_device_list(dev_list, 1); + return list; +} + +#ifndef LIBUSB_NO_HOTPLUG +void HWStubBackendHelper::OnHotPlug(bool arrived, struct libusb_device *dev) +{ + /* signal it */ + emit OnDevListChanged(arrived, dev); +} + +int HWStubBackendHelper::HotPlugCallback(struct libusb_context *ctx, struct libusb_device *dev, + libusb_hotplug_event event, void *user_data) +{ + HWStubBackendHelper *helper = reinterpret_cast< HWStubBackendHelper* >(user_data); + switch(event) + { + case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: helper->OnHotPlug(true, dev); break; + case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: helper->OnHotPlug(false, dev); break; + default: break; + } + return 0; +} +#endif + +bool HWStubBackendHelper::HasHotPlugSupport() +{ + return m_hotplug; +} + +#endif + +/** + * BackendHelper + */ + BackendHelper::BackendHelper(IoBackend *io_backend, const soc_t& soc) :m_io_backend(io_backend), m_soc(soc) { @@ -119,38 +333,87 @@ BackendHelper::BackendHelper(IoBackend *io_backend, const soc_t& soc) bool BackendHelper::ReadRegister(const QString& dev, const QString& reg, soc_word_t& v) { - return m_io_backend->ReadRegister("HW." + dev + "." + reg, v); + if(m_io_backend->SupportAccess(IoBackend::ByName)) + return m_io_backend->ReadRegister("HW." + dev + "." + reg, v); + if(m_io_backend->SupportAccess(IoBackend::ByAddress)) + { + soc_addr_t addr; + if(GetRegisterAddress(dev, reg, addr)) + return m_io_backend->ReadRegister(addr, v); + } + return false; } -bool BackendHelper::ReadRegisterField(const QString& dev, const QString& reg, - const QString& field, soc_word_t& v) + +bool BackendHelper::GetDeviceDesc(const QString& dev, soc_dev_t& dev_desc, size_t& index) { - soc_dev_t *sdev = 0; for(size_t i = 0; i < m_soc.dev.size(); i++) { for(size_t j = 0; j < m_soc.dev[i].addr.size(); j++) if(m_soc.dev[i].addr[j].name.c_str() == dev) - sdev = &m_soc.dev[i]; + { + dev_desc = m_soc.dev[i]; + index = j; + return true; + } } - if(sdev == 0) - return false; - soc_reg_t *sreg = 0; - for(size_t i = 0; i < sdev->reg.size(); i++) + return false; +} + +bool BackendHelper::GetRegisterDesc(const soc_dev_t& dev, const QString& reg, + soc_reg_t& reg_desc, size_t& index) +{ + for(size_t i = 0; i < dev.reg.size(); i++) { - for(size_t j = 0; j < sdev->reg[i].addr.size(); j++) - if(sdev->reg[i].addr[j].name.c_str() == reg) - sreg = &sdev->reg[i]; + for(size_t j = 0; j < dev.reg[i].addr.size(); j++) + if(dev.reg[i].addr[j].name.c_str() == reg) + { + index = j; + reg_desc = dev.reg[i]; + return true; + } } - if(sreg == 0) + return false; +} + +bool BackendHelper::GetFieldDesc(const soc_reg_t& reg_desc, const QString& field, + soc_reg_field_t& field_desc) +{ + for(size_t i = 0; i < reg_desc.field.size(); i++) + if(reg_desc.field[i].name.c_str() == field) + field_desc = reg_desc.field[i]; + return false; +} + +bool BackendHelper::GetRegisterAddress(const QString& dev, const QString& reg, + soc_addr_t& addr) +{ + size_t dev_index, reg_index; + soc_dev_t dev_desc; + soc_reg_t reg_desc; + if(!GetDeviceDesc(dev, dev_desc, dev_index)) + return false; + if(!GetRegisterDesc(dev_desc, reg, reg_desc, reg_index)) + return false; + addr = dev_desc.addr[dev_index].addr + reg_desc.addr[reg_index].addr; + return true; +} + +bool BackendHelper::ReadRegisterField(const QString& dev, const QString& reg, + const QString& field, soc_word_t& v) +{ + size_t dev_index, reg_index; + soc_dev_t dev_desc; + soc_reg_t reg_desc; + soc_reg_field_t field_desc; + if(!GetDeviceDesc(dev, dev_desc, dev_index)) + return false; + if(!GetRegisterDesc(dev_desc, reg, reg_desc, reg_index)) return false; - soc_reg_field_t *sfield = 0; - for(size_t i = 0; i < sreg->field.size(); i++) - if(sreg->field[i].name.c_str() == field) - sfield = &sreg->field[i]; - if(sfield == 0) + if(!GetFieldDesc(reg_desc, field, field_desc)) return false; if(!ReadRegister(dev, reg, v)) return false; - v = (v & sfield->bitmask()) >> sfield->first_bit; + v = (v & field_desc.bitmask()) >> field_desc.first_bit; return true; } \ No newline at end of file -- cgit v1.2.3