summaryrefslogtreecommitdiff
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.cpp376
1 files changed, 376 insertions, 0 deletions
diff --git a/utils/rbutilqt/base/autodetection.cpp b/utils/rbutilqt/base/autodetection.cpp
new file mode 100644
index 0000000000..341f219c30
--- /dev/null
+++ b/utils/rbutilqt/base/autodetection.cpp
@@ -0,0 +1,376 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2007 by Dominik Wenger
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include <QtCore>
20#include "autodetection.h"
21#include "rbsettings.h"
22#include "playerbuildinfo.h"
23
24#include "../ipodpatcher/ipodpatcher.h"
25#include "../sansapatcher/sansapatcher.h"
26
27
28#include "system.h"
29#include "utils.h"
30#include "rockboxinfo.h"
31#include "Logger.h"
32
33Autodetection::Autodetection(QObject* parent): QObject(parent)
34{
35}
36
37
38bool Autodetection::detect(void)
39{
40 QMap<PlayerStatus, QString> states;
41 states[PlayerOk] = "Ok";
42 states[PlayerAmbiguous] = "Ambiguous";
43 states[PlayerError] = "Error";
44 states[PlayerIncompatible] = "Incompatible";
45 states[PlayerMtpMode] = "MtpMode";
46
47 // clear detection state
48 m_detected.clear();
49
50 detectUsb();
51 mergeMounted();
52 mergePatcher();
53 // if any entry with usbdevices containing a value is left that entry
54 // hasn't been merged later. This indicates a problem during detection
55 // (ambiguous player but refining it failed). In this case create an entry
56 // for eacho of those so the user can select.
57 QList<struct Detected> detected;
58 for(int i = 0; i < m_detected.size(); ++i) {
59 int j = m_detected.at(i).usbdevices.size();
60 if(j > 0) {
61 struct Detected entry = m_detected.at(i);
62 while(j--) {
63 struct Detected d;
64 d.device = entry.usbdevices.at(j);
65 d.mountpoint = entry.mountpoint;
66 d.status = PlayerAmbiguous;
67 detected.append(d);
68 }
69 }
70 else {
71 detected.append(m_detected.at(i));
72 }
73 }
74 m_detected = detected;
75 for(int i = 0; i < m_detected.size(); ++i) {
76 LOG_INFO() << "Detected player:" << m_detected.at(i).device
77 << "at" << m_detected.at(i).mountpoint
78 << states[m_detected.at(i).status];
79 }
80
81 return m_detected.size() > 0;
82}
83
84
85/** @brief detect devices based on usb pid / vid.
86 */
87void Autodetection::detectUsb()
88{
89 // usb pid detection
90 QList<uint32_t> attached;
91 attached = System::listUsbIds();
92
93 int i = attached.size();
94 while(i--) {
95 QStringList a = PlayerBuildInfo::instance()->value(PlayerBuildInfo::UsbIdTargetList, attached.at(i)).toStringList();
96 if(a.size() > 0) {
97 struct Detected d;
98 d.status = PlayerOk;
99 d.usbdevices = a;
100 m_detected.append(d);
101 LOG_INFO() << "[USB] detected supported player" << d.usbdevices;
102 }
103 QStringList b = PlayerBuildInfo::instance()->value(PlayerBuildInfo::UsbIdErrorList, attached.at(i)).toStringList();
104 if(b.size() > 0) {
105 struct Detected d;
106 d.status = PlayerMtpMode;
107 d.usbdevices = b;
108 m_detected.append(d);
109 LOG_WARNING() << "[USB] detected problem with player" << d.device;
110 }
111 QString idstring = QString("%1").arg(attached.at(i), 8, 16, QChar('0'));
112 if(!PlayerBuildInfo::instance()->value(
113 PlayerBuildInfo::DisplayName, idstring).toString().isEmpty()) {
114 struct Detected d;
115 d.status = PlayerIncompatible;
116 d.device = idstring;
117 m_detected.append(d);
118 LOG_WARNING() << "[USB] detected incompatible player" << d.device;
119 }
120 }
121}
122
123
124// Merge players detected by checking mounted filesystems for known files:
125// - rockbox-info.txt / rbutil.log
126// - player specific files
127void Autodetection::mergeMounted(void)
128{
129 QStringList mounts = Utils::mountpoints(Utils::MountpointsSupported);
130 LOG_INFO() << "paths to check:" << mounts;
131
132 for(int i = 0; i < mounts.size(); i++)
133 {
134 // do the file checking
135 QDir dir(mounts.at(i));
136 if(dir.exists())
137 {
138 // check logfile first.
139 if(QFile(mounts.at(i) + "/.rockbox/rbutil.log").exists()) {
140 QSettings log(mounts.at(i) + "/.rockbox/rbutil.log",
141 QSettings::IniFormat, this);
142 if(!log.value("platform").toString().isEmpty()) {
143 struct Detected d;
144 d.device = log.value("platform").toString();
145 d.mountpoint = mounts.at(i);
146 d.status = PlayerOk;
147 updateDetectedDevice(d);
148 LOG_INFO() << "rbutil.log detected:"
149 << log.value("platform").toString() << mounts.at(i);
150 }
151 }
152
153 // check rockbox-info.txt afterwards.
154 RockboxInfo info(mounts.at(i));
155 if(info.success())
156 {
157 struct Detected d;
158 d.device = info.target();
159 d.mountpoint = mounts.at(i);
160 d.status = PlayerOk;
161 updateDetectedDevice(d);
162 LOG_INFO() << "rockbox-info.txt detected:"
163 << info.target() << mounts.at(i);
164 }
165
166 // check for some specific files in root folder
167 QDir root(mounts.at(i));
168 QStringList rootentries = root.entryList(QDir::Files);
169 if(rootentries.contains("archos.mod", Qt::CaseInsensitive))
170 {
171 // archos.mod in root folder -> Archos Player
172 struct Detected d;
173 d.device = "player";
174 d.mountpoint = mounts.at(i);
175 d.status = PlayerOk;
176 updateDetectedDevice(d);
177 }
178 if(rootentries.contains("ONDIOST.BIN", Qt::CaseInsensitive))
179 {
180 // ONDIOST.BIN in root -> Ondio FM
181 struct Detected d;
182 d.device = "ondiofm";
183 d.mountpoint = mounts.at(i);
184 d.status = PlayerOk;
185 updateDetectedDevice(d);
186 }
187 if(rootentries.contains("ONDIOSP.BIN", Qt::CaseInsensitive))
188 {
189 // ONDIOSP.BIN in root -> Ondio SP
190 struct Detected d;
191 d.device = "ondiosp";
192 d.mountpoint = mounts.at(i);
193 d.status = PlayerOk;
194 updateDetectedDevice(d);
195 }
196 if(rootentries.contains("ajbrec.ajz", Qt::CaseInsensitive))
197 {
198 LOG_INFO() << "ajbrec.ajz found. Trying detectAjbrec()";
199 struct Detected d;
200 d.device = detectAjbrec(mounts.at(i));
201 d.mountpoint = mounts.at(i);
202 d.status = PlayerOk;
203 if(!d.device.isEmpty()) {
204 LOG_INFO() << d.device;
205 updateDetectedDevice(d);
206 }
207 }
208 // detection based on player specific folders
209 QStringList rootfolders = root.entryList(QDir::Dirs
210 | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
211 if(rootfolders.contains("GBSYSTEM", Qt::CaseInsensitive))
212 {
213 // GBSYSTEM folder -> Gigabeat
214 struct Detected d;
215 d.device = "gigabeatf";
216 d.mountpoint = mounts.at(i);
217 updateDetectedDevice(d);
218 }
219 }
220 }
221#if 0
222 // Ipods have a folder "iPod_Control" in the root.
223 for(int i = 0; i < m_detected.size(); ++i) {
224 struct Detected entry = m_detected.at(i);
225 for(int j = 0; j < entry.usbdevices.size(); ++j) {
226 // limit this to Ipods only.
227 if(!entry.usbdevices.at(j).startsWith("ipod")
228 && !entry.device.startsWith("ipod")) {
229 continue;
230 }
231 // look for iPod_Control on all supported volumes.
232 for(int k = 0; k < mounts.size(); k++) {
233 QDir root(mounts.at(k));
234 QStringList rootfolders = root.entryList(QDir::Dirs
235 | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
236 if(rootfolders.contains("iPod_Control", Qt::CaseInsensitive)) {
237 entry.mountpoint = mounts.at(k);
238 m_detected.takeAt(i);
239 m_detected.append(entry);
240 }
241 }
242 }
243 }
244#endif
245
246}
247
248
249void Autodetection::mergePatcher(void)
250{
251 int n;
252 // try ipodpatcher
253 // initialize sector buffer. Needed.
254 struct ipod_t ipod;
255 ipod.sectorbuf = nullptr;
256 ipod_alloc_buffer(&ipod, BUFFER_SIZE);
257 n = ipod_scan(&ipod);
258 // FIXME: handle more than one Ipod connected in ipodpatcher.
259 if(n == 1) {
260 LOG_INFO() << "Ipod found:" << ipod.modelstr << "at" << ipod.diskname;
261 // since resolveMountPoint is doing exact matches we need to select
262 // the correct partition.
263 QString mp(ipod.diskname);
264#ifdef Q_OS_LINUX
265 mp.append("2");
266#endif
267#ifdef Q_OS_MACX
268 mp.append("s2");
269#endif
270 struct Detected d;
271 d.device = ipod.targetname;
272 d.mountpoint = Utils::resolveMountPoint(mp);
273 // if the found ipod is a macpod also notice it as device with problem.
274 if(ipod.macpod)
275 d.status = PlayerWrongFilesystem;
276 else
277 d.status = PlayerOk;
278 updateDetectedDevice(d);
279 }
280 else {
281 LOG_INFO() << "ipodpatcher: no Ipod found." << n;
282 }
283 ipod_dealloc_buffer(&ipod);
284
285 // try sansapatcher
286 // initialize sector buffer. Needed.
287 struct sansa_t sansa;
288 sansa_alloc_buffer(&sansa, BUFFER_SIZE);
289 n = sansa_scan(&sansa);
290 if(n == 1) {
291 LOG_INFO() << "Sansa found:"
292 << sansa.targetname << "at" << sansa.diskname;
293 QString mp(sansa.diskname);
294#ifdef Q_OS_LINUX
295 mp.append("1");
296#endif
297#ifdef Q_OS_MACX
298 mp.append("s1");
299#endif
300 struct Detected d;
301 d.device = QString("sansa%1").arg(sansa.targetname);
302 d.mountpoint = Utils::resolveMountPoint(mp);
303 d.status = PlayerOk;
304 updateDetectedDevice(d);
305 }
306 else {
307 LOG_INFO() << "sansapatcher: no Sansa found." << n;
308 }
309 sansa_dealloc_buffer(&sansa);
310}
311
312
313QString Autodetection::detectAjbrec(QString root)
314{
315 QFile f(root + "/ajbrec.ajz");
316 char header[24];
317 f.open(QIODevice::ReadOnly);
318 if(!f.read(header, 24)) return QString();
319 f.close();
320
321 // check the header of the file.
322 // recorder v1 had a 6 bytes sized header
323 // recorder v2, FM, Ondio SP and FM have a 24 bytes header.
324
325 // recorder v1 has the binary length in the first 4 bytes, so check
326 // for them first.
327 int len = (header[0]<<24) | (header[1]<<16) | (header[2]<<8) | header[3];
328 LOG_INFO() << "abjrec.ajz possible bin length:" << len
329 << "file len:" << f.size();
330 if((f.size() - 6) == len)
331 return "recorder";
332
333 // size didn't match, now we need to assume we have a headerlength of 24.
334 switch(header[11]) {
335 case 2:
336 return "recorderv2";
337 case 4:
338 return "fmrecorder";
339 case 8:
340 return "ondiofm";
341 case 16:
342 return "ondiosp";
343 default:
344 break;
345 }
346 return QString();
347}
348
349
350int Autodetection::findDetectedDevice(QString device)
351{
352 int i = m_detected.size();
353 while(i--) {
354 if(m_detected.at(i).usbdevices.contains(device))
355 return i;
356 }
357 i = m_detected.size();
358 while(i--) {
359 if(m_detected.at(i).device == device)
360 return i;
361 }
362 return -1;
363}
364
365
366void Autodetection::updateDetectedDevice(Detected& entry)
367{
368 int index = findDetectedDevice(entry.device);
369 if(index < 0) {
370 m_detected.append(entry);
371 }
372 else {
373 m_detected.takeAt(index);
374 m_detected.append(entry);
375 }
376}