summaryrefslogtreecommitdiff
path: root/rbutil/rbutilqt/base/autodetection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/rbutilqt/base/autodetection.cpp')
-rw-r--r--rbutil/rbutilqt/base/autodetection.cpp391
1 files changed, 391 insertions, 0 deletions
diff --git a/rbutil/rbutilqt/base/autodetection.cpp b/rbutil/rbutilqt/base/autodetection.cpp
new file mode 100644
index 0000000000..67e95b998d
--- /dev/null
+++ b/rbutil/rbutilqt/base/autodetection.cpp
@@ -0,0 +1,391 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2007 by Dominik Wenger
10 * $Id$
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <QtCore>
21#include "autodetection.h"
22
23#if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
24#include <stdio.h>
25#include <usb.h>
26#endif
27#if defined(Q_OS_LINUX)
28#include <mntent.h>
29#endif
30#if defined(Q_OS_MACX)
31#include <sys/param.h>
32#include <sys/ucred.h>
33#include <sys/mount.h>
34#endif
35#if defined(Q_OS_WIN32)
36#if defined(UNICODE)
37#define _UNICODE
38#endif
39#include <stdio.h>
40#include <tchar.h>
41#include <windows.h>
42#include <setupapi.h>
43#include <winioctl.h>
44#endif
45#include "detect.h"
46#include "utils.h"
47
48Autodetection::Autodetection(QObject* parent): QObject(parent)
49{
50
51}
52
53bool Autodetection::detect()
54{
55 m_device = "";
56 m_mountpoint = "";
57 m_errdev = "";
58
59 detectUsb();
60
61 // Try detection via rockbox.info / rbutil.log
62 QStringList mountpoints = getMountpoints();
63
64 for(int i=0; i< mountpoints.size();i++)
65 {
66 // do the file checking
67 QDir dir(mountpoints.at(i));
68 qDebug() << "paths to check for player specific files:" << mountpoints;
69 if(dir.exists())
70 {
71 // check logfile first.
72 if(QFile(mountpoints.at(i) + "/.rockbox/rbutil.log").exists()) {
73 QSettings log(mountpoints.at(i) + "/.rockbox/rbutil.log",
74 QSettings::IniFormat, this);
75 if(!log.value("platform").toString().isEmpty()) {
76 if(m_device.isEmpty())
77 m_device = log.value("platform").toString();
78 m_mountpoint = mountpoints.at(i);
79 qDebug() << "rbutil.log detected:" << m_device << m_mountpoint;
80 return true;
81 }
82 }
83
84 // check rockbox-info.txt afterwards.
85 QFile file(mountpoints.at(i) + "/.rockbox/rockbox-info.txt");
86 if(file.exists())
87 {
88 file.open(QIODevice::ReadOnly | QIODevice::Text);
89 QString line = file.readLine();
90 if(line.startsWith("Target: "))
91 {
92 line.remove("Target: ");
93 if(m_device.isEmpty())
94 m_device = line.trimmed(); // trim whitespaces
95 m_mountpoint = mountpoints.at(i);
96 qDebug() << "rockbox-info.txt detected:" << m_device << m_mountpoint;
97 return true;
98 }
99 }
100 // check for some specific files in root folder
101 QDir root(mountpoints.at(i));
102 QStringList rootentries = root.entryList(QDir::Files);
103 if(rootentries.contains("archos.mod", Qt::CaseInsensitive))
104 {
105 // archos.mod in root folder -> Archos Player
106 m_device = "player";
107 m_mountpoint = mountpoints.at(i);
108 return true;
109 }
110 if(rootentries.contains("ONDIOST.BIN", Qt::CaseInsensitive))
111 {
112 // ONDIOST.BIN in root -> Ondio FM
113 m_device = "ondiofm";
114 m_mountpoint = mountpoints.at(i);
115 return true;
116 }
117 if(rootentries.contains("ONDIOSP.BIN", Qt::CaseInsensitive))
118 {
119 // ONDIOSP.BIN in root -> Ondio SP
120 m_device = "ondiosp";
121 m_mountpoint = mountpoints.at(i);
122 return true;
123 }
124 if(rootentries.contains("ajbrec.ajz", Qt::CaseInsensitive))
125 {
126 qDebug() << "ajbrec.ajz found. Trying detectAjbrec()";
127 if(detectAjbrec(mountpoints.at(i))) {
128 m_mountpoint = mountpoints.at(i);
129 qDebug() << m_device;
130 return true;
131 }
132 }
133 // detection based on player specific folders
134 QStringList rootfolders = root.entryList(QDir::Dirs
135 | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
136 if(rootfolders.contains("GBSYSTEM", Qt::CaseInsensitive))
137 {
138 // GBSYSTEM folder -> Gigabeat
139 m_device = "gigabeatf";
140 m_mountpoint = mountpoints.at(i);
141 return true;
142 }
143#if defined(Q_OS_WIN32)
144 // on windows, try to detect the drive letter of an Ipod
145 if(rootfolders.contains("iPod_Control", Qt::CaseInsensitive))
146 {
147 // iPod_Control folder -> Ipod found
148 // detecting of the Ipod type is done below using ipodpatcher
149 m_mountpoint = mountpoints.at(i);
150 }
151#endif
152 }
153
154 }
155
156 int n;
157 // try ipodpatcher
158 // initialize sector buffer. Needed.
159 ipod_sectorbuf = NULL;
160 ipod_alloc_buffer(&ipod_sectorbuf, BUFFER_SIZE);
161 struct ipod_t ipod;
162 n = ipod_scan(&ipod);
163 if(n == 1) {
164 qDebug() << "Ipod found:" << ipod.modelstr << "at" << ipod.diskname;
165 m_device = ipod.targetname;
166 m_mountpoint = resolveMountPoint(ipod.diskname);
167 return true;
168 }
169 else {
170 qDebug() << "ipodpatcher: no Ipod found." << n;
171 }
172 free(ipod_sectorbuf);
173 ipod_sectorbuf = NULL;
174
175 // try sansapatcher
176 // initialize sector buffer. Needed.
177 sansa_sectorbuf = NULL;
178 sansa_alloc_buffer(&sansa_sectorbuf, BUFFER_SIZE);
179 struct sansa_t sansa;
180 n = sansa_scan(&sansa);
181 if(n == 1) {
182 qDebug() << "Sansa found:" << sansa.targetname << "at" << sansa.diskname;
183 m_device = QString("sansa%1").arg(sansa.targetname);
184 m_mountpoint = resolveMountPoint(sansa.diskname);
185 return true;
186 }
187 else {
188 qDebug() << "sansapatcher: no Sansa found." << n;
189 }
190 free(sansa_sectorbuf);
191 sansa_sectorbuf = NULL;
192
193 if(m_mountpoint.isEmpty() && m_device.isEmpty() && m_errdev.isEmpty() && m_incompat.isEmpty())
194 return false;
195 return true;
196}
197
198
199QStringList Autodetection::getMountpoints()
200{
201 QStringList tempList;
202#if defined(Q_OS_WIN32)
203 QFileInfoList list = QDir::drives();
204 for(int i=0; i<list.size();i++)
205 {
206 tempList << list.at(i).absolutePath();
207 }
208
209#elif defined(Q_OS_MACX)
210 int num;
211 struct statfs *mntinf;
212
213 num = getmntinfo(&mntinf, MNT_WAIT);
214 while(num--) {
215 tempList << QString(mntinf->f_mntonname);
216 mntinf++;
217 }
218#elif defined(Q_OS_LINUX)
219
220 FILE *mn = setmntent("/etc/mtab", "r");
221 if(!mn)
222 return QStringList("");
223
224 struct mntent *ent;
225 while((ent = getmntent(mn)))
226 tempList << QString(ent->mnt_dir);
227 endmntent(mn);
228
229#else
230#error Unknown Plattform
231#endif
232 return tempList;
233}
234
235QString Autodetection::resolveMountPoint(QString device)
236{
237 qDebug() << "Autodetection::resolveMountPoint(QString)" << device;
238
239#if defined(Q_OS_LINUX)
240 FILE *mn = setmntent("/etc/mtab", "r");
241 if(!mn)
242 return QString("");
243
244 struct mntent *ent;
245 while((ent = getmntent(mn))) {
246 if(QString(ent->mnt_fsname).startsWith(device)
247 && QString(ent->mnt_type).contains("vfat", Qt::CaseInsensitive)) {
248 endmntent(mn);
249 return QString(ent->mnt_dir);
250 }
251 }
252 endmntent(mn);
253
254#endif
255
256#if defined(Q_OS_MACX)
257 int num;
258 struct statfs *mntinf;
259
260 num = getmntinfo(&mntinf, MNT_WAIT);
261 while(num--) {
262 if(QString(mntinf->f_mntfromname).startsWith(device)
263 && QString(mntinf->f_fstypename).contains("vfat", Qt::CaseInsensitive))
264 return QString(mntinf->f_mntonname);
265 mntinf++;
266 }
267#endif
268
269#if defined(Q_OS_WIN32)
270 QString result;
271 unsigned int driveno = device.replace(QRegExp("^.*([0-9]+)"), "\\1").toInt();
272
273 for(int letter = 'A'; letter <= 'Z'; letter++) {
274 DWORD written;
275 HANDLE h;
276 TCHAR uncpath[MAX_PATH];
277 UCHAR buffer[0x400];
278 PVOLUME_DISK_EXTENTS extents = (PVOLUME_DISK_EXTENTS)buffer;
279
280 _stprintf(uncpath, _TEXT("\\\\.\\%c:"), letter);
281 h = CreateFile(uncpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
282 NULL, OPEN_EXISTING, 0, NULL);
283 if(h == INVALID_HANDLE_VALUE) {
284 //qDebug() << "error getting extents for" << uncpath;
285 continue;
286 }
287 // get the extents
288 if(DeviceIoControl(h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
289 NULL, 0, extents, sizeof(buffer), &written, NULL)) {
290 for(unsigned int a = 0; a < extents->NumberOfDiskExtents; a++) {
291 qDebug() << "Disk:" << extents->Extents[a].DiskNumber;
292 if(extents->Extents[a].DiskNumber == driveno) {
293 result = letter;
294 qDebug("drive found for volume %i: %c", driveno, letter);
295 break;
296 }
297 }
298
299 }
300
301 }
302 if(!result.isEmpty())
303 return result + ":/";
304#endif
305 return QString("");
306}
307
308
309/** @brief detect devices based on usb pid / vid.
310 * @return true upon success, false otherwise.
311 */
312bool Autodetection::detectUsb()
313{
314 // usbids holds the mapping in the form
315 // ((VID<<16)|(PID)), targetname
316 // the ini file needs to hold the IDs as hex values.
317 QMap<int, QString> usbids = settings->usbIdMap();
318 QMap<int, QString> usberror = settings->usbIdErrorMap();
319 QMap<int, QString> usbincompat = settings->usbIdIncompatMap();
320
321 // usb pid detection
322 QList<uint32_t> attached;
323 attached = Detect::listUsbIds();
324
325 int i = attached.size();
326 while(i--) {
327 if(usbids.contains(attached.at(i))) {
328 m_device = usbids.value(attached.at(i));
329 qDebug() << "[USB] detected supported player" << m_device;
330 return true;
331 }
332 if(usberror.contains(attached.at(i))) {
333 m_errdev = usberror.value(attached.at(i));
334 qDebug() << "[USB] detected problem with player" << m_errdev;
335 return true;
336 }
337 if(usbincompat.contains(attached.at(i))) {
338 m_incompat = usbincompat.value(attached.at(i));
339 qDebug() << "[USB] detected incompatible player" << m_incompat;
340 return true;
341 }
342 }
343 return false;
344}
345
346
347bool Autodetection::detectAjbrec(QString root)
348{
349 QFile f(root + "/ajbrec.ajz");
350 char header[24];
351 f.open(QIODevice::ReadOnly);
352 if(!f.read(header, 24)) return false;
353
354 // check the header of the file.
355 // recorder v1 had a 6 bytes sized header
356 // recorder v2, FM, Ondio SP and FM have a 24 bytes header.
357
358 // recorder v1 has the binary length in the first 4 bytes, so check
359 // for them first.
360 int len = (header[0]<<24) | (header[1]<<16) | (header[2]<<8) | header[3];
361 qDebug() << "possible bin length:" << len;
362 qDebug() << "file len:" << f.size();
363 if((f.size() - 6) == len)
364 m_device = "recorder";
365
366 // size didn't match, now we need to assume we have a headerlength of 24.
367 switch(header[11]) {
368 case 2:
369 m_device = "recorderv2";
370 break;
371
372 case 4:
373 m_device = "fmrecorder";
374 break;
375
376 case 8:
377 m_device = "ondiofm";
378 break;
379
380 case 16:
381 m_device = "ondiosp";
382 break;
383
384 default:
385 break;
386 }
387 f.close();
388
389 if(m_device.isEmpty()) return false;
390 return true;
391}