1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * Copyright (C) 2007 by Dominik Wenger
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "autodetection.h"
22 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
26 #if defined(Q_OS_LINUX)
29 #if defined(Q_OS_MACX)
30 #include <sys/param.h>
31 #include <sys/ucred.h>
32 #include <sys/mount.h>
34 #if defined(Q_OS_WIN32)
44 Autodetection::Autodetection(QObject
* parent
): QObject(parent
)
49 bool Autodetection::detect()
57 // Try detection via rockbox.info / rbutil.log
58 QStringList mountpoints
= getMountpoints();
60 for(int i
=0; i
< mountpoints
.size();i
++)
62 // do the file checking
63 QDir
dir(mountpoints
.at(i
));
66 qDebug() << "file checking:" << mountpoints
.at(i
);
67 // check logfile first.
68 if(QFile(mountpoints
.at(i
) + "/.rockbox/rbutil.log").exists()) {
69 QSettings
log(mountpoints
.at(i
) + "/.rockbox/rbutil.log",
70 QSettings::IniFormat
, this);
71 if(!log
.value("platform").toString().isEmpty()) {
72 if(m_device
.isEmpty())
73 m_device
= log
.value("platform").toString();
74 m_mountpoint
= mountpoints
.at(i
);
75 qDebug() << "rbutil.log detected:" << m_device
<< m_mountpoint
;
80 // check rockbox-info.txt afterwards.
81 QFile
file(mountpoints
.at(i
) + "/.rockbox/rockbox-info.txt");
84 file
.open(QIODevice::ReadOnly
| QIODevice::Text
);
85 QString line
= file
.readLine();
86 if(line
.startsWith("Target: "))
88 line
.remove("Target: ");
89 if(m_device
.isEmpty())
90 m_device
= line
.trimmed(); // trim whitespaces
91 m_mountpoint
= mountpoints
.at(i
);
92 qDebug() << "rockbox-info.txt detected:" << m_device
<< m_mountpoint
;
96 // check for some specific files in root folder
97 QDir
root(mountpoints
.at(i
));
98 QStringList rootentries
= root
.entryList(QDir::Files
);
99 if(rootentries
.contains("archos.mod", Qt::CaseInsensitive
))
101 // archos.mod in root folder -> Archos Player
103 m_mountpoint
= mountpoints
.at(i
);
106 if(rootentries
.contains("ONDIOST.BIN", Qt::CaseInsensitive
))
108 // ONDIOST.BIN in root -> Ondio FM
109 m_device
= "ondiofm";
110 m_mountpoint
= mountpoints
.at(i
);
113 if(rootentries
.contains("ONDIOSP.BIN", Qt::CaseInsensitive
))
115 // ONDIOSP.BIN in root -> Ondio SP
116 m_device
= "ondiosp";
117 m_mountpoint
= mountpoints
.at(i
);
120 if(rootentries
.contains("ajbrec.ajz", Qt::CaseInsensitive
))
122 qDebug() << "ajbrec.ajz found. Trying detectAjbrec()";
123 if(detectAjbrec(mountpoints
.at(i
))) {
124 m_mountpoint
= mountpoints
.at(i
);
125 qDebug() << m_device
;
129 // detection based on player specific folders
130 QStringList rootfolders
= root
.entryList(QDir::Dirs
131 | QDir::NoDotAndDotDot
| QDir::Hidden
| QDir::System
);
132 if(rootfolders
.contains("GBSYSTEM", Qt::CaseInsensitive
))
134 // GBSYSTEM folder -> Gigabeat
135 m_device
= "gigabeatf";
136 m_mountpoint
= mountpoints
.at(i
);
139 #if defined(Q_OS_WIN32)
140 // on windows, try to detect the drive letter of an Ipod
141 if(rootfolders
.contains("iPod_Control", Qt::CaseInsensitive
))
143 // iPod_Control folder -> Ipod found
144 // detecting of the Ipod type is done below using ipodpatcher
145 m_mountpoint
= mountpoints
.at(i
);
155 n
= ipod_scan(&ipod
);
157 qDebug() << "Ipod found:" << ipod
.modelstr
<< "at" << ipod
.diskname
;
158 m_device
= ipod
.targetname
;
159 #if !defined(Q_OS_WIN32)
160 m_mountpoint
= resolveMountPoint(ipod
.diskname
);
166 struct sansa_t sansa
;
167 n
= sansa_scan(&sansa
);
169 qDebug() << "Sansa found:" << sansa
.targetname
<< "at" << sansa
.diskname
;
170 m_device
= QString("sansa%1").arg(sansa
.targetname
);
171 m_mountpoint
= resolveMountPoint(sansa
.diskname
);
175 if(m_mountpoint
.isEmpty() && m_device
.isEmpty() && m_errdev
.isEmpty() && m_incompat
.isEmpty())
181 QStringList
Autodetection::getMountpoints()
183 QStringList tempList
;
184 #if defined(Q_OS_WIN32)
185 QFileInfoList list
= QDir::drives();
186 for(int i
=0; i
<list
.size();i
++)
188 tempList
<< list
.at(i
).absolutePath();
191 #elif defined(Q_OS_MACX)
193 struct statfs
*mntinf
;
195 num
= getmntinfo(&mntinf
, MNT_WAIT
);
197 tempList
<< QString(mntinf
->f_mntonname
);
200 #elif defined(Q_OS_LINUX)
202 FILE *mn
= setmntent("/etc/mtab", "r");
204 return QStringList("");
207 while((ent
= getmntent(mn
)))
208 tempList
<< QString(ent
->mnt_dir
);
212 #error Unknown Plattform
217 QString
Autodetection::resolveMountPoint(QString device
)
219 qDebug() << "Autodetection::resolveMountPoint(QString)" << device
;
221 #if defined(Q_OS_LINUX)
222 FILE *mn
= setmntent("/etc/mtab", "r");
227 while((ent
= getmntent(mn
))) {
228 if(QString(ent
->mnt_fsname
).startsWith(device
)
229 && QString(ent
->mnt_type
).contains("vfat", Qt::CaseInsensitive
)) {
231 return QString(ent
->mnt_dir
);
238 #if defined(Q_OS_MACX)
240 struct statfs
*mntinf
;
242 num
= getmntinfo(&mntinf
, MNT_WAIT
);
244 if(QString(mntinf
->f_mntfromname
).startsWith(device
)
245 && QString(mntinf
->f_fstypename
).contains("vfat", Qt::CaseInsensitive
))
246 return QString(mntinf
->f_mntonname
);
255 /** @brief detect devices based on usb pid / vid.
256 * @return true upon success, false otherwise.
258 bool Autodetection::detectUsb()
260 // usbids holds the mapping in the form
261 // ((VID<<16)|(PID)), targetname
262 // the ini file needs to hold the IDs as hex values.
263 QMap
<int, QString
> usbids
= settings
->usbIdMap();
264 QMap
<int, QString
> usberror
= settings
->usbIdErrorMap();
265 QMap
<int, QString
> usbincompat
= settings
->usbIdIncompatMap();
268 #if defined(Q_OS_LINUX) | defined(Q_OS_MACX)
273 b
= usb_get_busses();
276 qDebug() << "bus:" << b
->dirname
<< b
->devices
;
278 qDebug() << "devices present.";
279 struct usb_device
*u
;
283 id
= u
->descriptor
.idVendor
<< 16 | u
->descriptor
.idProduct
;
284 m_usbconid
.append(id
);
287 if(usbids
.contains(id
)) {
288 m_device
= usbids
.value(id
);
291 if(usberror
.contains(id
)) {
292 m_errdev
= usberror
.value(id
);
293 // we detected something, so return true
294 qDebug() << "detected device with problems via usb!";
297 if(usbincompat
.contains(id
)) {
298 m_incompat
= usbincompat
.value(id
);
299 qDebug() << "detected incompatible player variant";
309 #if defined(Q_OS_WIN32)
311 SP_DEVINFO_DATA infoData
;
314 // Iterate over all devices
315 // by doing it this way it's unneccessary to use GUIDs which might be not
316 // present in current MinGW. It also seemed to be more reliably than using
318 // See KB259695 for an example.
319 deviceInfo
= SetupDiGetClassDevs(NULL
, NULL
, NULL
, DIGCF_ALLCLASSES
| DIGCF_PRESENT
);
321 infoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
323 for(i
= 0; SetupDiEnumDeviceInfo(deviceInfo
, i
, &infoData
); i
++) {
325 LPTSTR buffer
= NULL
;
326 DWORD buffersize
= 0;
328 // get device desriptor first
329 // for some reason not doing so results in bad things (tm)
330 while(!SetupDiGetDeviceRegistryProperty(deviceInfo
, &infoData
,
331 SPDRP_DEVICEDESC
,&data
, (PBYTE
)buffer
, buffersize
, &buffersize
)) {
332 if(GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
333 if(buffer
) free(buffer
);
334 // double buffer size to avoid problems as per KB888609
335 buffer
= (LPTSTR
)malloc(buffersize
* 2);
342 // now get the hardware id, which contains PID and VID.
343 while(!SetupDiGetDeviceRegistryProperty(deviceInfo
, &infoData
,
344 SPDRP_HARDWAREID
,&data
, (PBYTE
)buffer
, buffersize
, &buffersize
)) {
345 if(GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
346 if(buffer
) free(buffer
);
347 // double buffer size to avoid problems as per KB888609
348 buffer
= (LPTSTR
)malloc(buffersize
* 2);
355 unsigned int vid
, pid
, rev
;
356 if(_stscanf(buffer
, _TEXT("USB\\Vid_%x&Pid_%x&Rev_%x"), &vid
, &pid
, &rev
) != 3) {
357 qDebug() << "Error getting USB ID -- possibly no USB device";
361 id
= vid
<< 16 | pid
;
362 m_usbconid
.append(id
);
363 qDebug("VID: %04x PID: %04x", vid
, pid
);
364 if(usbids
.contains(id
)) {
365 m_device
= usbids
.value(id
);
366 if(buffer
) free(buffer
);
367 SetupDiDestroyDeviceInfoList(deviceInfo
);
368 qDebug() << "detectUsb: Got" << m_device
;
371 if(usberror
.contains(id
)) {
372 m_errdev
= usberror
.value(id
);
373 // we detected something, so return true
374 if(buffer
) free(buffer
);
375 SetupDiDestroyDeviceInfoList(deviceInfo
);
376 qDebug() << "detectUsb: Got" << m_device
;
377 qDebug() << "detected device with problems via usb!";
380 if(usbincompat
.contains(id
)) {
381 m_incompat
= usbincompat
.value(id
);
382 // we detected an incompatible player variant
383 if(buffer
) free(buffer
);
384 SetupDiDestroyDeviceInfoList(deviceInfo
);
385 qDebug() << "detectUsb: detected incompatible variant";
389 if(buffer
) free(buffer
);
391 SetupDiDestroyDeviceInfoList(deviceInfo
);
398 bool Autodetection::detectAjbrec(QString root
)
400 QFile
f(root
+ "/ajbrec.ajz");
402 f
.open(QIODevice::ReadOnly
);
403 if(!f
.read(header
, 24)) return false;
405 // check the header of the file.
406 // recorder v1 had a 6 bytes sized header
407 // recorder v2, FM, Ondio SP and FM have a 24 bytes header.
409 // recorder v1 has the binary length in the first 4 bytes, so check
411 int len
= (header
[0]<<24) | (header
[1]<<16) | (header
[2]<<8) | header
[3];
412 qDebug() << "possible bin length:" << len
;
413 qDebug() << "file len:" << f
.size();
414 if((f
.size() - 6) == len
)
415 m_device
= "recorder";
417 // size didn't match, now we need to assume we have a headerlength of 24.
420 m_device
= "recorderv2";
424 m_device
= "fmrecorder";
428 m_device
= "ondiofm";
432 m_device
= "ondiosp";
440 if(m_device
.isEmpty()) return false;