A modern, network-enabled music player platform built on Rockbox technology. rockboxd.tsiry-sandratraina.com
rust deno navidrome airplay libadwaita zig mpris snapcast mpd rockbox audio subsonic
2

Configure Feed

Select the types of activity you want to include in your feed.

rockboxd / utils / regtools / qeditor / backend.cpp
25 kB 1038 lines
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * 9 * Copyright (C) 2014 by Amaury Pouly 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 2 14 * of the License, or (at your option) any later version. 15 * 16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 17 * KIND, either express or implied. 18 * 19 ****************************************************************************/ 20#include <QFile> 21#include <QTextStream> 22#include <QDebug> 23#include <QFileInfo> 24#include <QFont> 25#include "backend.h" 26 27/** 28 * SocFile 29 */ 30SocFile::SocFile() 31 :m_valid(true) 32{ 33} 34 35SocFile::SocFile(const QString& filename) 36 :m_filename(filename) 37{ 38 soc_desc::error_context_t ctx; 39 m_valid = soc_desc::parse_xml(filename.toStdString(), m_soc, ctx); 40} 41 42bool SocFile::IsValid() 43{ 44 return m_valid; 45} 46 47soc_desc::soc_ref_t SocFile::GetSocRef() 48{ 49 if(m_valid) 50 return soc_desc::soc_ref_t(&m_soc); 51 else 52 return soc_desc::soc_ref_t(); 53} 54 55QString SocFile::GetFilename() 56{ 57 return m_filename; 58} 59 60/** 61 * Backend 62 */ 63 64Backend::Backend() 65{ 66} 67 68 69QList< SocFileRef > Backend::GetSocFileList() 70{ 71 QList< SocFileRef > list; 72 for(std::list< SocFile >::iterator it = m_socs.begin(); it != m_socs.end(); ++it) 73 { 74 if(it->IsValid()) 75 list.append(SocFileRef(&(*it))); 76 } 77 return list; 78} 79 80QList< soc_desc::soc_ref_t > Backend::GetSocList() 81{ 82 QList< soc_desc::soc_ref_t > list; 83 for(std::list< SocFile >::iterator it = m_socs.begin(); it != m_socs.end(); ++it) 84 { 85 soc_desc::soc_ref_t r = it->GetSocRef(); 86 if(r.valid()) 87 list.append(r); 88 } 89 return list; 90} 91 92bool Backend::LoadSocDesc(const QString& filename) 93{ 94 SocFile f(filename); 95 if(!f.IsValid()) 96 return false; 97 m_socs.push_back(f); 98 emit OnSocAdded(SocFileRef(&m_socs.back())); 99 return true; 100} 101 102IoBackend *Backend::CreateFileIoBackend(const QString& filename) 103{ 104 return new FileIoBackend(filename); 105} 106 107IoBackend *Backend::CreateDummyIoBackend() 108{ 109 return new DummyIoBackend(); 110} 111 112#ifdef HAVE_HWSTUB 113IoBackend *Backend::CreateHWStubIoBackend(HWStubDevice *dev) 114{ 115 return new HWStubIoBackend(dev); 116} 117#endif 118 119/** 120 * DummyIoBackend 121 */ 122 123DummyIoBackend::DummyIoBackend() 124{ 125} 126 127bool DummyIoBackend::IsValid() 128{ 129 return false; 130} 131 132QString DummyIoBackend::GetSocName() 133{ 134 return ""; 135} 136 137bool DummyIoBackend::ReadRegister(soc_addr_t addr, soc_word_t& value, 138 unsigned width) 139{ 140 Q_UNUSED(addr); 141 Q_UNUSED(value); 142 Q_UNUSED(width); 143 return false; 144} 145 146bool DummyIoBackend::Reload() 147{ 148 return false; 149} 150 151bool DummyIoBackend::IsReadOnly() 152{ 153 return true; 154} 155 156bool DummyIoBackend::WriteRegister(soc_addr_t addr, soc_word_t value, 157 unsigned width, WriteMode mode) 158{ 159 Q_UNUSED(addr); 160 Q_UNUSED(value); 161 Q_UNUSED(mode); 162 Q_UNUSED(width); 163 return false; 164} 165 166bool DummyIoBackend::IsDirty() 167{ 168 return false; 169} 170 171bool DummyIoBackend::Commit() 172{ 173 return false; 174} 175 176/** 177 * RamIoBackend 178 */ 179RamIoBackend::RamIoBackend(const QString& soc_name) 180{ 181 m_soc = soc_name; 182} 183 184bool RamIoBackend::IsValid() 185{ 186 return m_soc != ""; 187} 188 189QString RamIoBackend::GetSocName() 190{ 191 return m_soc; 192} 193 194void RamIoBackend::SetSocName(const QString& soc_name) 195{ 196 m_soc = soc_name; 197} 198 199bool RamIoBackend::RamIoBackend::Reload() 200{ 201 return false; 202} 203 204bool RamIoBackend::IsReadOnly() 205{ 206 return false; 207} 208 209bool RamIoBackend::ReadRegister(soc_addr_t addr, soc_word_t& value, 210 unsigned width) 211{ 212 Q_UNUSED(width); 213 QMap<soc_addr_t, soc_word_t>::const_iterator it = m_map.find(addr); 214 if(it == m_map.end()) 215 return false; 216 value = it.value(); 217 return true; 218} 219 220void RamIoBackend::DeleteAll() 221{ 222 m_map.clear(); 223} 224 225bool RamIoBackend::WriteRegister(soc_addr_t addr, soc_word_t value, 226 unsigned width, WriteMode mode) 227{ 228 Q_UNUSED(width); 229 switch(mode) 230 { 231 case Write: m_map[addr] = value; return true; 232 case Set: m_map[addr] |= value; return true; 233 case Clear: m_map[addr] &= ~value; return true; 234 case Toggle: m_map[addr] ^= value; return true; 235 default: return false; 236 } 237} 238 239bool RamIoBackend::IsDirty() 240{ 241 return false; 242} 243 244bool RamIoBackend::Commit() 245{ 246 return false; 247} 248 249/** 250 * FileIoBackend 251 */ 252 253FileIoBackend::FileIoBackend(const QString& filename, const QString& soc_name) 254 :RamIoBackend(soc_name) 255{ 256 m_filename = filename; 257 m_valid = false; 258 Reload(); 259} 260 261bool FileIoBackend::IsValid() 262{ 263 return m_valid; 264} 265 266bool FileIoBackend::Reload() 267{ 268 m_valid = false; 269 QFile file(m_filename); 270 if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) 271 return false; 272 DeleteAll(); 273 274 QTextStream in(&file); 275 while(!in.atEnd()) 276 { 277 QString line = in.readLine(); 278 int idx = line.indexOf('='); 279 if(idx == -1) 280 continue; 281 QString key_str = line.left(idx).trimmed(); 282 QString val_str = line.mid(idx + 1).trimmed(); 283 bool key_ok,val_ok; 284 soc_word_t val = val_str.toULong(&val_ok, 0); 285 soc_word_t key = key_str.toULong(&key_ok, 0); 286 if(key_str == "soc") 287 m_soc = val_str; 288 else if(key_ok && val_ok) 289 RamIoBackend::WriteRegister(key, val, 32, Write); 290 } 291 m_readonly = !QFileInfo(file).isWritable(); 292 m_dirty = false; 293 m_valid = true; 294 return true; 295} 296 297bool FileIoBackend::WriteRegister(soc_addr_t addr, soc_word_t value, 298 unsigned width, WriteMode mode) 299{ 300 m_dirty = true; 301 return RamIoBackend::WriteRegister(addr, value, width, mode); 302} 303 304bool FileIoBackend::Commit() 305{ 306 if(!m_dirty) 307 return true; 308 QFile file(m_filename); 309 if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) 310 return false; 311 QTextStream out(&file); 312 out << "soc = " << m_soc << "\n"; 313 QMapIterator< soc_addr_t, soc_word_t > it(m_map); 314 while(it.hasNext()) 315 { 316 it.next(); 317 out << hex << showbase << it.key() << " = " << hex << showbase << it.value() << "\n"; 318 } 319 out.flush(); 320 return file.flush(); 321} 322 323bool FileIoBackend::IsReadOnly() 324{ 325 return m_readonly; 326} 327 328bool FileIoBackend::IsDirty() 329{ 330 return m_dirty; 331} 332 333QString FileIoBackend::GetFileName() 334{ 335 return m_filename; 336} 337 338#ifdef HAVE_HWSTUB 339/** 340 * HWStubManager 341 */ 342HWStubManager *HWStubManager::g_inst = nullptr; 343 344HWStubManager::HWStubManager() 345{ 346 Add("Default", QString::fromStdString(hwstub::uri::default_uri().full_uri())); 347} 348 349HWStubManager::~HWStubManager() 350{ 351} 352 353HWStubManager *HWStubManager::Get() 354{ 355 if(g_inst == nullptr) 356 g_inst = new HWStubManager(); 357 return g_inst; 358} 359 360bool HWStubManager::Add(const QString& name, const QString& uri) 361{ 362 struct Context ctx; 363 ctx.name = name; 364 ctx.uri = uri; 365 ctx.context = hwstub::uri::create_context(uri.toStdString()); 366 if(!ctx.context) 367 return false; 368 ctx.context->start_polling(); 369 beginInsertRows(QModelIndex(), m_list.size(), m_list.size()); 370 m_list.push_back(ctx); 371 endInsertRows(); 372 return true; 373} 374 375void HWStubManager::Clear() 376{ 377 m_list.clear(); 378} 379 380int HWStubManager::rowCount(const QModelIndex& parent) const 381{ 382 Q_UNUSED(parent); 383 return m_list.size(); 384} 385 386int HWStubManager::columnCount(const QModelIndex& parent) const 387{ 388 Q_UNUSED(parent); 389 return 2; 390} 391 392std::shared_ptr< hwstub::context > HWStubManager::GetContext(int row) 393{ 394 if(row < 0 || (size_t)row >= m_list.size()) 395 return std::shared_ptr< hwstub::context >(); 396 else 397 return m_list[row].context; 398} 399 400QVariant HWStubManager::data(const QModelIndex& index, int role) const 401{ 402 if(index.row() < 0 || (size_t)index.row() >= m_list.size()) 403 return QVariant(); 404 int section = index.column(); 405 const Context& ctx = m_list[index.row()]; 406 if(section == GetNameColumn()) 407 { 408 if(role == Qt::DisplayRole || role == Qt::EditRole) 409 return QVariant(ctx.name); 410 } 411 else if(section == GetUriColumn()) 412 { 413 if(role == Qt::DisplayRole) 414 return QVariant(ctx.uri); 415 } 416 return QVariant(); 417} 418 419QVariant HWStubManager::headerData(int section, Qt::Orientation orientation, int role) const 420{ 421 if(orientation == Qt::Vertical) 422 return QVariant(); 423 if(role != Qt::DisplayRole) 424 return QVariant(); 425 if(section == GetNameColumn()) 426 return QVariant("Name"); 427 else if(section == GetUriColumn()) 428 return QVariant("URI"); 429 return QVariant(); 430} 431 432Qt::ItemFlags HWStubManager::flags(const QModelIndex& index) const 433{ 434 Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; 435 int section = index.column(); 436 if(section == GetNameColumn()) 437 flags |= Qt::ItemIsEditable; 438 return flags; 439} 440 441bool HWStubManager::setData(const QModelIndex& index, const QVariant& value, int role) 442{ 443 if(role != Qt::EditRole) 444 return false; 445 if(index.row() < 0 || (size_t)index.row() >= m_list.size()) 446 return false; 447 if(index.column() != GetNameColumn()) 448 return false; 449 m_list[index.row()].name = value.toString(); 450 emit dataChanged(index, index); 451 return true; 452} 453 454int HWStubManager::GetNameColumn() const 455{ 456 return 0; 457} 458 459int HWStubManager::GetUriColumn() const 460{ 461 return 1; 462} 463 464QString HWStubManager::GetFriendlyName(std::shared_ptr< hwstub::device > device) 465{ 466 /* try to open the device */ 467 std::shared_ptr< hwstub::handle > handle; 468 hwstub::error err = device->open(handle); 469 if(err != hwstub::error::SUCCESS) 470 goto Lfallback; 471 /* get target descriptor */ 472 struct hwstub_target_desc_t target_desc; 473 err = handle->get_target_desc(target_desc); 474 if(err != hwstub::error::SUCCESS) 475 goto Lfallback; 476 return QString::fromStdString(target_desc.bName); 477 478 /* fallback: don't open the device */ 479Lfallback: 480 hwstub::usb::device *udev = dynamic_cast< hwstub::usb::device* >(device.get()); 481 if(udev) 482 { 483 return QString("USB Bus %1 Device %2: ID %3:%4") 484 .arg(udev->get_bus_number()).arg(udev->get_address(), 3, 10, QChar('0')) 485 .arg(udev->get_vid(), 4, 16, QChar('0')).arg(udev->get_pid(), 4, 16, QChar('0')); 486 } 487 else 488 return QString("<Unknown device>"); 489} 490 491/** 492 * HWStubContextModel 493 */ 494HWStubContextModel::HWStubContextModel(QObject *parent) 495 :QAbstractTableModel(parent), m_has_dummy(false) 496{ 497} 498 499HWStubContextModel::~HWStubContextModel() 500{ 501 SetContext(std::shared_ptr< hwstub::context >()); 502} 503 504void HWStubContextModel::SetContext(std::shared_ptr< hwstub::context > context) 505{ 506 int first_row = m_has_dummy ? 1: 0; 507 /* clear previous model if any */ 508 if(m_list.size() > 0) 509 { 510 beginRemoveRows(QModelIndex(), first_row, first_row + m_list.size() - 1); 511 m_list.clear(); 512 endRemoveRows(); 513 } 514 /* don't forget to unregister callback if context still exists */ 515 std::shared_ptr< hwstub::context > ctx = m_context.lock(); 516 if(ctx) 517 ctx->unregister_callback(m_callback_ref); 518 /* get new context */ 519 m_context = context; 520 if(context) 521 { 522 /* register new callback */ 523 m_callback_ref = context->register_callback( 524 std::bind(&HWStubContextModel::OnDevChangeLow, this, std::placeholders::_1, 525 std::placeholders::_2, std::placeholders::_3)); 526 /* get dev list */ 527 std::vector< std::shared_ptr< hwstub::device > > list; 528 hwstub::error err = context->get_device_list(list); 529 if(err == hwstub::error::SUCCESS) 530 { 531 beginInsertRows(QModelIndex(), first_row, first_row + list.size() - 1); 532 for(auto& d : list) 533 { 534 Device dev; 535 dev.name = GetFriendlyName(d); 536 dev.device = d; 537 m_list.push_back(dev); 538 } 539 endInsertRows(); 540 } 541 } 542} 543 544void HWStubContextModel::EnableDummy(bool en, const QString& text) 545{ 546 /* if needed, create/remove raw */ 547 if(m_has_dummy && !en) 548 { 549 /* remove row */ 550 beginRemoveRows(QModelIndex(), 0, 0); 551 m_has_dummy = false; 552 endRemoveRows(); 553 } 554 else if(!m_has_dummy && en) 555 { 556 /* add row */ 557 beginInsertRows(QModelIndex(), 0, 0); 558 m_has_dummy = true; 559 m_dummy_text = text; 560 endInsertRows(); 561 } 562 else if(en) 563 { 564 /* text change only */ 565 emit dataChanged(index(0, GetNameColumn()), index(0, GetNameColumn())); 566 } 567} 568 569int HWStubContextModel::rowCount(const QModelIndex& parent) const 570{ 571 Q_UNUSED(parent); 572 return m_list.size() + (m_has_dummy ? 1 : 0); 573} 574 575int HWStubContextModel::columnCount(const QModelIndex& parent) const 576{ 577 Q_UNUSED(parent); 578 return 1; 579} 580 581QVariant HWStubContextModel::data(const QModelIndex& index, int role) const 582{ 583 int first_row = m_has_dummy ? 1: 0; 584 /* special case for dummy */ 585 if(m_has_dummy && index.row() == 0) 586 { 587 int section = index.column(); 588 if(section == GetNameColumn()) 589 { 590 if(role == Qt::DisplayRole) 591 return QVariant(m_dummy_text); 592 else if(role == Qt::FontRole) 593 { 594 QFont font; 595 font.setItalic(true); 596 return QVariant(font); 597 } 598 } 599 return QVariant(); 600 } 601 602 if(index.row() < first_row || (size_t)index.row() >= first_row + m_list.size()) 603 return QVariant(); 604 int section = index.column(); 605 if(section == GetNameColumn()) 606 { 607 if(role == Qt::DisplayRole) 608 return QVariant(m_list[index.row() - first_row].name); 609 } 610 return QVariant(); 611} 612 613QVariant HWStubContextModel::headerData(int section, Qt::Orientation orientation, int role) const 614{ 615 if(orientation == Qt::Vertical) 616 return QVariant(); 617 if(role != Qt::DisplayRole) 618 return QVariant(); 619 if(section == GetNameColumn()) 620 return QVariant("Friendly name"); 621 return QVariant(); 622} 623 624Qt::ItemFlags HWStubContextModel::flags(const QModelIndex& index) const 625{ 626 Q_UNUSED(index); 627 return Qt::ItemIsSelectable | Qt::ItemIsEnabled; 628} 629 630int HWStubContextModel::GetNameColumn() const 631{ 632 return 0; 633} 634 635std::shared_ptr< hwstub::device > HWStubContextModel::GetDevice(int row) 636{ 637 int first_row = m_has_dummy ? 1: 0; 638 /* special case for dummy */ 639 if(row < first_row || (size_t)row >= first_row + m_list.size()) 640 return std::shared_ptr< hwstub::device >(); 641 else 642 return m_list[row - first_row].device; 643} 644 645QString HWStubContextModel::GetFriendlyName(std::shared_ptr< hwstub::device > device) 646{ 647 return HWStubManager::GetFriendlyName(device); 648} 649 650namespace 651{ 652 struct dev_change_t 653 { 654 std::shared_ptr< hwstub::context > ctx; 655 bool arrived; 656 std::shared_ptr< hwstub::device > device; 657 }; 658} 659 660void HWStubContextModel::OnDevChangeLow(std::shared_ptr< hwstub::context > ctx, 661 bool arrived, std::shared_ptr< hwstub::device > device) 662{ 663 /* calling Qt function from non-Qt thread is unsafe. Since the polling thread 664 * is a pthread, the safest way to use Qt invoke mecanism to make it run 665 * on the event loop */ 666 dev_change_t *evt = new dev_change_t; 667 evt->ctx = ctx; 668 evt->arrived = arrived; 669 evt->device = device; 670 QMetaObject::invokeMethod(this, "OnDevChangeUnsafe", Q_ARG(void *, (void *)evt)); 671} 672 673void HWStubContextModel::OnDevChangeUnsafe(void *data) 674{ 675 dev_change_t *evt = (dev_change_t *)data; 676 OnDevChange(evt->ctx, evt->arrived, evt->device); 677 delete evt; 678} 679 680void HWStubContextModel::OnDevChange(std::shared_ptr< hwstub::context > ctx, bool arrived, 681 std::shared_ptr< hwstub::device > device) 682{ 683 int first_row = m_has_dummy ? 1: 0; 684 Q_UNUSED(ctx); 685 if(arrived) 686 { 687 Device dev; 688 dev.name = GetFriendlyName(device); 689 dev.device = device; 690 beginInsertRows(QModelIndex(), first_row + m_list.size(), 691 first_row + m_list.size()); 692 m_list.push_back(dev); 693 endInsertRows(); 694 } 695 else 696 { 697 /* find device in the list */ 698 auto it = m_list.begin(); 699 int idx = 0; 700 for(; it != m_list.end(); ++it, ++idx) 701 if(it->device == device) 702 break; 703 if(it == m_list.end()) 704 return; 705 /* remove it */ 706 beginRemoveRows(QModelIndex(), first_row + idx, first_row + idx); 707 m_list.erase(it); 708 endRemoveRows(); 709 } 710} 711 712/** 713 * HWStubDevice 714 */ 715HWStubDevice::HWStubDevice(std::shared_ptr< hwstub::device > device) 716{ 717 m_valid = Probe(device); 718} 719 720HWStubDevice::~HWStubDevice() 721{ 722} 723 724bool HWStubDevice::Probe(std::shared_ptr<hwstub::device> device) 725{ 726 if(!device) 727 return false; 728 hwstub::error err = device->open(m_handle); 729 if(err != hwstub::error::SUCCESS) 730 return false; 731 // get target information 732 err = m_handle->get_target_desc(m_hwdev_target); 733 if(err != hwstub::error::SUCCESS) 734 return false; 735 // get STMP/PP information 736 if(m_hwdev_target.dID == HWSTUB_TARGET_STMP) 737 { 738 err = m_handle->get_stmp_desc(m_hwdev_stmp); 739 if(err != hwstub::error::SUCCESS) 740 return false; 741 } 742 else if(m_hwdev_target.dID == HWSTUB_TARGET_PP) 743 { 744 err = m_handle->get_pp_desc(m_hwdev_pp); 745 if(err != hwstub::error::SUCCESS) 746 return false; 747 } 748 else if(m_hwdev_target.dID == HWSTUB_TARGET_JZ) 749 { 750 err = m_handle->get_jz_desc(m_hwdev_jz); 751 if(err != hwstub::error::SUCCESS) 752 return false; 753 } 754 m_name = HWStubManager::GetFriendlyName(device); 755 return true; 756} 757 758bool HWStubDevice::ReadMem(soc_addr_t addr, size_t length, void *buffer) 759{ 760 size_t len = length; 761 hwstub::error err = m_handle->read(addr, buffer, len, true); 762 return err == hwstub::error::SUCCESS && len == length; 763} 764 765bool HWStubDevice::WriteMem(soc_addr_t addr, size_t length, void *buffer) 766{ 767 size_t len = length; 768 hwstub::error err = m_handle->write(addr, buffer, len, true); 769 return err == hwstub::error::SUCCESS && len == length; 770} 771 772bool HWStubDevice::IsValid() 773{ 774 return m_valid; 775} 776 777QString HWStubDevice::GetFriendlyName() 778{ 779 return m_name; 780} 781 782/** 783 * HWStubIoBackend 784 */ 785 786HWStubIoBackend::HWStubIoBackend(HWStubDevice *dev) 787{ 788 m_dev = dev; 789 790 struct hwstub_target_desc_t target = m_dev->GetTargetInfo(); 791 if(target.dID == HWSTUB_TARGET_STMP) 792 { 793 struct hwstub_stmp_desc_t stmp = m_dev->GetSTMPInfo(); 794 if(stmp.wChipID == 0x3780) 795 m_soc = "imx233"; 796 else if(stmp.wChipID >= 0x3700 && stmp.wChipID < 0x3780) 797 m_soc = "stmp3700"; 798 else if(stmp.wChipID >= 0x3600 && stmp.wChipID < 0x3700) 799 m_soc = "stmp3600"; 800 else 801 m_soc = QString("stmp%1").arg(stmp.wChipID, 4, 16, QChar('0')); 802 } 803 else if(target.dID == HWSTUB_TARGET_JZ) 804 { 805 struct hwstub_jz_desc_t jz = m_dev->GetJZInfo(); 806 m_soc = QString("jz%1").arg(jz.wChipID, 4, 16, QChar('0')); 807 if(jz.bRevision != 0) 808 m_soc.append(QChar(jz.bRevision).toLower()); 809 } 810 else if(target.dID == HWSTUB_TARGET_RK27) 811 m_soc = "rk27x"; 812 else if(target.dID == HWSTUB_TARGET_PP) 813 { 814 struct hwstub_pp_desc_t pp = m_dev->GetPPInfo(); 815 if(pp.wChipID == 0x6110 ) 816 m_soc = "pp6110"; 817 else 818 m_soc = QString("pp%1").arg(pp.wChipID, 4, 16, QChar('0')); 819 } 820 else if(target.dID == HWSTUB_TARGET_ATJ) 821 m_soc = "atj213x"; 822 else 823 m_soc = target.bName; 824} 825 826QString HWStubIoBackend::GetSocName() 827{ 828 return m_soc; 829} 830 831HWStubIoBackend::~HWStubIoBackend() 832{ 833 delete m_dev; 834} 835 836bool HWStubIoBackend::IsValid() 837{ 838 return m_dev->IsValid(); 839} 840 841bool HWStubIoBackend::IsReadOnly() 842{ 843 return false; 844} 845 846bool HWStubIoBackend::IsDirty() 847{ 848 return false; 849} 850 851bool HWStubIoBackend::Commit() 852{ 853 return true; 854} 855 856HWStubDevice *HWStubIoBackend::GetDevice() 857{ 858 return m_dev; 859} 860 861bool HWStubIoBackend::ReadRegister(soc_addr_t addr, soc_word_t& value, 862 unsigned width) 863{ 864 if(width != 8 && width != 16 && width != 32) 865 return false; 866 return m_dev->ReadMem(addr, width / 8, &value); 867} 868 869bool HWStubIoBackend::WriteRegister(soc_addr_t addr, soc_word_t value, 870 unsigned width, WriteMode mode) 871{ 872 if(width != 8 && width != 16 && width != 32) 873 return false; 874 switch(mode) 875 { 876 case Set: addr += 4; break; 877 case Clear: addr += 8; break; 878 case Toggle: addr += 12; break; 879 default: break; 880 } 881 return m_dev->WriteMem(addr, width / 8, &value); 882} 883 884bool HWStubIoBackend::Reload() 885{ 886 return true; 887} 888 889#endif /* HAVE_HWSTUB */ 890 891/** 892 * BackendHelper 893 */ 894 895BackendHelper::BackendHelper(IoBackend *io_backend, const soc_desc::soc_ref_t& soc) 896 :m_io_backend(io_backend), m_soc(soc) 897{ 898} 899 900QString BackendHelper::GetPath(const soc_desc::node_inst_t& inst) 901{ 902 if(!inst.valid() || inst.is_root()) 903 return QString(); 904 QString s = GetPath(inst.parent()); 905 if(!s.isEmpty()) 906 s += "."; 907 s += inst.name().c_str(); 908 if(inst.is_indexed()) 909 s = QString("%1[%2]").arg(s).arg(inst.index()); 910 return s; 911} 912 913soc_desc::node_inst_t BackendHelper::ParsePath(const QString& path) 914{ 915 soc_desc::node_inst_t inst = m_soc.root_inst(); 916 /* empty path is root */ 917 if(path.isEmpty()) 918 return inst; 919 int pos = 0; 920 while(pos < path.size()) 921 { 922 /* try to find the next separator */ 923 int next = path.indexOf('.', pos); 924 if(next == -1) 925 next = path.size(); 926 /* try to find the index, if any */ 927 int lidx = path.indexOf('[', pos); 928 if(lidx == -1 || lidx > next) 929 lidx = next; 930 /* extract name */ 931 std::string name = path.mid(pos, lidx - pos).toStdString(); 932 /* and index */ 933 if(lidx < next) 934 { 935 int ridx = path.indexOf(']', lidx + 1); 936 /* syntax error ? */ 937 if(ridx == -1 || ridx > next) 938 return soc_desc::node_inst_t(); 939 /* invalid number ? */ 940 bool ok = false; 941 size_t idx = path.mid(lidx + 1, ridx - lidx - 1).toUInt(&ok); 942 if(ok) 943 inst = inst.child(name, idx); 944 else 945 inst = soc_desc::node_inst_t(); 946 } 947 else 948 inst = inst.child(name); 949 /* advance right after the separator */ 950 pos = next + 1; 951 } 952 return inst; 953} 954 955bool BackendHelper::ReadRegister(const soc_desc::node_inst_t& inst, 956 soc_word_t& v) 957{ 958 soc_addr_t addr; 959 if(!GetRegisterAddress(inst, addr)) 960 return false; 961 return m_io_backend->ReadRegister(addr, v, inst.node().reg().get()->width); 962} 963 964bool BackendHelper::WriteRegister(const soc_desc::node_inst_t& inst, 965 soc_word_t v, IoBackend::WriteMode mode) 966{ 967 soc_addr_t addr; 968 if(!GetRegisterAddress(inst, addr)) 969 return false; 970 return m_io_backend->WriteRegister(addr, v, inst.node().reg().get()->width, mode); 971} 972 973bool BackendHelper::GetRegisterAddress(const soc_desc::node_inst_t& inst, 974 soc_addr_t& addr) 975{ 976 if(!inst.valid()) 977 return false; 978 addr = inst.addr(); 979 return true; 980} 981 982bool BackendHelper::ReadRegisterField(const soc_desc::node_inst_t& inst, 983 const QString& field, soc_word_t& v) 984{ 985 soc_desc::field_ref_t ref = inst.node().reg().field(field.toStdString()); 986 if(!ref.valid()) 987 return false; 988 if(!ReadRegister(inst, v)) 989 return false; 990 v = (v & ref.get()->bitmask()) >> ref.get()->pos; 991 return true; 992} 993 994bool BackendHelper::DumpAllRegisters(const QString& filename, bool ignore_errors) 995{ 996 FileIoBackend b(filename, QString::fromStdString(m_soc.get()->name)); 997 bool ret = DumpAllRegisters(&b, ignore_errors); 998 return ret && b.Commit(); 999} 1000 1001bool BackendHelper::DumpAllRegisters(IoBackend *backend, bool ignore_errors) 1002{ 1003 BackendHelper helper(backend, m_soc); 1004 return DumpAllRegisters(&helper, m_soc.root_inst(), ignore_errors); 1005} 1006 1007bool BackendHelper::DumpAllRegisters(BackendHelper *bh, 1008 const soc_desc::node_inst_t& inst, bool ignore_errors) 1009{ 1010 bool ret = true; 1011 if(inst.node().reg().valid()) 1012 { 1013 soc_word_t val; 1014 if(!ReadRegister(inst, val)) 1015 { 1016 ret = false; 1017 if(!ignore_errors) 1018 return false; 1019 } 1020 else if(!bh->WriteRegister(inst, val)) 1021 { 1022 ret = false; 1023 if(!ignore_errors) 1024 return false; 1025 } 1026 } 1027 std::vector< soc_desc::node_inst_t > list = inst.children(); 1028 for(size_t i = 0; i < list.size(); i++) 1029 { 1030 if(!DumpAllRegisters(bh, list[i], ignore_errors)) 1031 { 1032 ret = false; 1033 if(!ignore_errors) 1034 return false; 1035 } 1036 } 1037 return ret; 1038}