summaryrefslogtreecommitdiffstats
path: root/utils/rbutilqt/base/autodetection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/rbutilqt/base/autodetection.cpp')
-rw-r--r--utils/rbutilqt/base/autodetection.cpp378
1 files changed, 378 insertions, 0 deletions
diff --git a/utils/rbutilqt/base/autodetection.cpp b/utils/rbutilqt/base/autodetection.cpp
new file mode 100644
index 0000000000..5021e1b3cc
--- /dev/null
+++ b/utils/rbutilqt/base/autodetection.cpp
@@ -0,0 +1,378 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2007 by Dominik Wenger
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <QtCore>
+#include "autodetection.h"
+#include "rbsettings.h"
+#include "playerbuildinfo.h"
+
+#include "../ipodpatcher/ipodpatcher.h"
+#include "../sansapatcher/sansapatcher.h"
+
+
+#include "system.h"
+#include "utils.h"
+#include "rockboxinfo.h"
+#include "Logger.h"
+
+Autodetection::Autodetection(QObject* parent): QObject(parent)
+{
+}
+
+
+bool Autodetection::detect(void)
+{
+ QMap<PlayerStatus, QString> states;
+ states[PlayerOk] = "Ok";
+ states[PlayerAmbiguous] = "Ambiguous";
+ states[PlayerError] = "Error";
+ states[PlayerIncompatible] = "Incompatible";
+ states[PlayerMtpMode] = "MtpMode";
+
+ // clear detection state
+ m_detected.clear();
+
+ detectUsb();
+ mergeMounted();
+ mergePatcher();
+ // if any entry with usbdevices containing a value is left that entry
+ // hasn't been merged later. This indicates a problem during detection
+ // (ambiguous player but refining it failed). In this case create an entry
+ // for eacho of those so the user can select.
+ QList<struct Detected> detected;
+ for(int i = 0; i < m_detected.size(); ++i) {
+ int j = m_detected.at(i).usbdevices.size();
+ if(j > 0) {
+ struct Detected entry = m_detected.at(i);
+ while(j--) {
+ struct Detected d;
+ d.device = entry.usbdevices.at(j);
+ d.mountpoint = entry.mountpoint;
+ d.status = PlayerAmbiguous;
+ detected.append(d);
+ }
+ }
+ else {
+ detected.append(m_detected.at(i));
+ }
+ }
+ m_detected = detected;
+ for(int i = 0; i < m_detected.size(); ++i) {
+ LOG_INFO() << "Detected player:" << m_detected.at(i).device
+ << "at" << m_detected.at(i).mountpoint
+ << states[m_detected.at(i).status];
+ }
+
+ return m_detected.size() > 0;
+}
+
+
+/** @brief detect devices based on usb pid / vid.
+ */
+void Autodetection::detectUsb()
+{
+ // usb pid detection
+ QList<uint32_t> attached;
+ attached = System::listUsbIds();
+
+ int i = attached.size();
+ while(i--) {
+ QStringList a = PlayerBuildInfo::instance()->value(
+ PlayerBuildInfo::UsbIdTargetList, attached.at(i)).toStringList();
+ if(a.size() > 0) {
+ struct Detected d;
+ d.status = PlayerOk;
+ d.usbdevices = a;
+ m_detected.append(d);
+ LOG_INFO() << "[USB] detected supported player" << d.usbdevices;
+ }
+ QStringList b = PlayerBuildInfo::instance()->value(
+ PlayerBuildInfo::UsbIdErrorList, attached.at(i)).toStringList();
+ if(b.size() > 0) {
+ struct Detected d;
+ d.status = PlayerMtpMode;
+ d.usbdevices = b;
+ m_detected.append(d);
+ LOG_WARNING() << "[USB] detected problem with player" << d.device;
+ }
+ QString idstring = QString("%1").arg(attached.at(i), 8, 16, QChar('0'));
+ if(!PlayerBuildInfo::instance()->value(
+ PlayerBuildInfo::DisplayName, idstring).toString().isEmpty()) {
+ struct Detected d;
+ d.status = PlayerIncompatible;
+ d.device = idstring;
+ m_detected.append(d);
+ LOG_WARNING() << "[USB] detected incompatible player" << d.device;
+ }
+ }
+}
+
+
+// Merge players detected by checking mounted filesystems for known files:
+// - rockbox-info.txt / rbutil.log
+// - player specific files
+void Autodetection::mergeMounted(void)
+{
+ QStringList mounts = Utils::mountpoints(Utils::MountpointsSupported);
+ LOG_INFO() << "paths to check:" << mounts;
+
+ for(int i = 0; i < mounts.size(); i++)
+ {
+ // do the file checking
+ QDir dir(mounts.at(i));
+ if(dir.exists())
+ {
+ // check logfile first.
+ if(QFile(mounts.at(i) + "/.rockbox/rbutil.log").exists()) {
+ QSettings log(mounts.at(i) + "/.rockbox/rbutil.log",
+ QSettings::IniFormat, this);
+ if(!log.value("platform").toString().isEmpty()) {
+ struct Detected d;
+ d.device = log.value("platform").toString();
+ d.mountpoint = mounts.at(i);
+ d.status = PlayerOk;
+ updateDetectedDevice(d);
+ LOG_INFO() << "rbutil.log detected:"
+ << log.value("platform").toString() << mounts.at(i);
+ }
+ }
+
+ // check rockbox-info.txt afterwards.
+ RockboxInfo info(mounts.at(i));
+ if(info.success())
+ {
+ struct Detected d;
+ d.device = info.target();
+ d.mountpoint = mounts.at(i);
+ d.status = PlayerOk;
+ updateDetectedDevice(d);
+ LOG_INFO() << "rockbox-info.txt detected:"
+ << info.target() << mounts.at(i);
+ }
+
+ // check for some specific files in root folder
+ QDir root(mounts.at(i));
+ QStringList rootentries = root.entryList(QDir::Files);
+ if(rootentries.contains("archos.mod", Qt::CaseInsensitive))
+ {
+ // archos.mod in root folder -> Archos Player
+ struct Detected d;
+ d.device = "player";
+ d.mountpoint = mounts.at(i);
+ d.status = PlayerOk;
+ updateDetectedDevice(d);
+ }
+ if(rootentries.contains("ONDIOST.BIN", Qt::CaseInsensitive))
+ {
+ // ONDIOST.BIN in root -> Ondio FM
+ struct Detected d;
+ d.device = "ondiofm";
+ d.mountpoint = mounts.at(i);
+ d.status = PlayerOk;
+ updateDetectedDevice(d);
+ }
+ if(rootentries.contains("ONDIOSP.BIN", Qt::CaseInsensitive))
+ {
+ // ONDIOSP.BIN in root -> Ondio SP
+ struct Detected d;
+ d.device = "ondiosp";
+ d.mountpoint = mounts.at(i);
+ d.status = PlayerOk;
+ updateDetectedDevice(d);
+ }
+ if(rootentries.contains("ajbrec.ajz", Qt::CaseInsensitive))
+ {
+ LOG_INFO() << "ajbrec.ajz found. Trying detectAjbrec()";
+ struct Detected d;
+ d.device = detectAjbrec(mounts.at(i));
+ d.mountpoint = mounts.at(i);
+ d.status = PlayerOk;
+ if(!d.device.isEmpty()) {
+ LOG_INFO() << d.device;
+ updateDetectedDevice(d);
+ }
+ }
+ // detection based on player specific folders
+ QStringList rootfolders = root.entryList(QDir::Dirs
+ | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
+ if(rootfolders.contains("GBSYSTEM", Qt::CaseInsensitive))
+ {
+ // GBSYSTEM folder -> Gigabeat
+ struct Detected d;
+ d.device = "gigabeatf";
+ d.mountpoint = mounts.at(i);
+ updateDetectedDevice(d);
+ }
+ }
+ }
+#if 0
+ // Ipods have a folder "iPod_Control" in the root.
+ for(int i = 0; i < m_detected.size(); ++i) {
+ struct Detected entry = m_detected.at(i);
+ for(int j = 0; j < entry.usbdevices.size(); ++j) {
+ // limit this to Ipods only.
+ if(!entry.usbdevices.at(j).startsWith("ipod")
+ && !entry.device.startsWith("ipod")) {
+ continue;
+ }
+ // look for iPod_Control on all supported volumes.
+ for(int k = 0; k < mounts.size(); k++) {
+ QDir root(mounts.at(k));
+ QStringList rootfolders = root.entryList(QDir::Dirs
+ | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
+ if(rootfolders.contains("iPod_Control", Qt::CaseInsensitive)) {
+ entry.mountpoint = mounts.at(k);
+ m_detected.takeAt(i);
+ m_detected.append(entry);
+ }
+ }
+ }
+ }
+#endif
+
+}
+
+
+void Autodetection::mergePatcher(void)
+{
+ int n;
+ // try ipodpatcher
+ // initialize sector buffer. Needed.
+ struct ipod_t ipod;
+ ipod.sectorbuf = nullptr;
+ ipod_alloc_buffer(&ipod, BUFFER_SIZE);
+ n = ipod_scan(&ipod);
+ // FIXME: handle more than one Ipod connected in ipodpatcher.
+ if(n == 1) {
+ LOG_INFO() << "Ipod found:" << ipod.modelstr << "at" << ipod.diskname;
+ // since resolveMountPoint is doing exact matches we need to select
+ // the correct partition.
+ QString mp(ipod.diskname);
+#ifdef Q_OS_LINUX
+ mp.append("2");
+#endif
+#ifdef Q_OS_MACX
+ mp.append("s2");
+#endif
+ struct Detected d;
+ d.device = ipod.targetname;
+ d.mountpoint = Utils::resolveMountPoint(mp);
+ // if the found ipod is a macpod also notice it as device with problem.
+ if(ipod.macpod)
+ d.status = PlayerWrongFilesystem;
+ else
+ d.status = PlayerOk;
+ updateDetectedDevice(d);
+ }
+ else {
+ LOG_INFO() << "ipodpatcher: no Ipod found." << n;
+ }
+ ipod_dealloc_buffer(&ipod);
+
+ // try sansapatcher
+ // initialize sector buffer. Needed.
+ struct sansa_t sansa;
+ sansa_alloc_buffer(&sansa, BUFFER_SIZE);
+ n = sansa_scan(&sansa);
+ if(n == 1) {
+ LOG_INFO() << "Sansa found:"
+ << sansa.targetname << "at" << sansa.diskname;
+ QString mp(sansa.diskname);
+#ifdef Q_OS_LINUX
+ mp.append("1");
+#endif
+#ifdef Q_OS_MACX
+ mp.append("s1");
+#endif
+ struct Detected d;
+ d.device = QString("sansa%1").arg(sansa.targetname);
+ d.mountpoint = Utils::resolveMountPoint(mp);
+ d.status = PlayerOk;
+ updateDetectedDevice(d);
+ }
+ else {
+ LOG_INFO() << "sansapatcher: no Sansa found." << n;
+ }
+ sansa_dealloc_buffer(&sansa);
+}
+
+
+QString Autodetection::detectAjbrec(const QString& root)
+{
+ QFile f(root + "/ajbrec.ajz");
+ char header[24];
+ f.open(QIODevice::ReadOnly);
+ if(!f.read(header, 24)) return QString();
+ f.close();
+
+ // check the header of the file.
+ // recorder v1 had a 6 bytes sized header
+ // recorder v2, FM, Ondio SP and FM have a 24 bytes header.
+
+ // recorder v1 has the binary length in the first 4 bytes, so check
+ // for them first.
+ int len = (header[0]<<24) | (header[1]<<16) | (header[2]<<8) | header[3];
+ LOG_INFO() << "abjrec.ajz possible bin length:" << len
+ << "file len:" << f.size();
+ if((f.size() - 6) == len)
+ return "recorder";
+
+ // size didn't match, now we need to assume we have a headerlength of 24.
+ switch(header[11]) {
+ case 2:
+ return "recorderv2";
+ case 4:
+ return "fmrecorder";
+ case 8:
+ return "ondiofm";
+ case 16:
+ return "ondiosp";
+ default:
+ break;
+ }
+ return QString();
+}
+
+
+int Autodetection::findDetectedDevice(const QString& device)
+{
+ int i = m_detected.size();
+ while(i--) {
+ if(m_detected.at(i).usbdevices.contains(device))
+ return i;
+ }
+ i = m_detected.size();
+ while(i--) {
+ if(m_detected.at(i).device == device)
+ return i;
+ }
+ return -1;
+}
+
+
+void Autodetection::updateDetectedDevice(Detected& entry)
+{
+ int index = findDetectedDevice(entry.device);
+ if(index < 0) {
+ m_detected.append(entry);
+ }
+ else {
+ m_detected.takeAt(index);
+ m_detected.append(entry);
+ }
+}