diff options
Diffstat (limited to 'rbutil/rbutilqt/base/autodetection.cpp')
-rw-r--r-- | rbutil/rbutilqt/base/autodetection.cpp | 391 |
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 | |||
48 | Autodetection::Autodetection(QObject* parent): QObject(parent) | ||
49 | { | ||
50 | |||
51 | } | ||
52 | |||
53 | bool 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 | |||
199 | QStringList 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 | |||
235 | QString 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 | */ | ||
312 | bool 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 | |||
347 | bool 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 | } | ||