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