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)
47 Autodetection::Autodetection(QObject
* parent
): QObject(parent
)
52 bool Autodetection::detect()
60 // Try detection via rockbox.info / rbutil.log
61 QStringList mountpoints
= getMountpoints();
63 for(int i
=0; i
< mountpoints
.size();i
++)
65 // do the file checking
66 QDir
dir(mountpoints
.at(i
));
69 qDebug() << "file checking:" << mountpoints
.at(i
);
70 // check logfile first.
71 if(QFile(mountpoints
.at(i
) + "/.rockbox/rbutil.log").exists()) {
72 QSettings
log(mountpoints
.at(i
) + "/.rockbox/rbutil.log",
73 QSettings::IniFormat
, this);
74 if(!log
.value("platform").toString().isEmpty()) {
75 if(m_device
.isEmpty())
76 m_device
= log
.value("platform").toString();
77 m_mountpoint
= mountpoints
.at(i
);
78 qDebug() << "rbutil.log detected:" << m_device
<< m_mountpoint
;
83 // check rockbox-info.txt afterwards.
84 QFile
file(mountpoints
.at(i
) + "/.rockbox/rockbox-info.txt");
87 file
.open(QIODevice::ReadOnly
| QIODevice::Text
);
88 QString line
= file
.readLine();
89 if(line
.startsWith("Target: "))
91 line
.remove("Target: ");
92 if(m_device
.isEmpty())
93 m_device
= line
.trimmed(); // trim whitespaces
94 m_mountpoint
= mountpoints
.at(i
);
95 qDebug() << "rockbox-info.txt detected:" << m_device
<< m_mountpoint
;
99 // check for some specific files in root folder
100 QDir
root(mountpoints
.at(i
));
101 QStringList rootentries
= root
.entryList(QDir::Files
);
102 if(rootentries
.contains("archos.mod", Qt::CaseInsensitive
))
104 // archos.mod in root folder -> Archos Player
106 m_mountpoint
= mountpoints
.at(i
);
109 if(rootentries
.contains("ONDIOST.BIN", Qt::CaseInsensitive
))
111 // ONDIOST.BIN in root -> Ondio FM
112 m_device
= "ondiofm";
113 m_mountpoint
= mountpoints
.at(i
);
116 if(rootentries
.contains("ONDIOSP.BIN", Qt::CaseInsensitive
))
118 // ONDIOSP.BIN in root -> Ondio SP
119 m_device
= "ondiosp";
120 m_mountpoint
= mountpoints
.at(i
);
123 if(rootentries
.contains("ajbrec.ajz", Qt::CaseInsensitive
))
125 qDebug() << "ajbrec.ajz found. Trying detectAjbrec()";
126 if(detectAjbrec(mountpoints
.at(i
))) {
127 m_mountpoint
= mountpoints
.at(i
);
128 qDebug() << m_device
;
132 // detection based on player specific folders
133 QStringList rootfolders
= root
.entryList(QDir::Dirs
134 | QDir::NoDotAndDotDot
| QDir::Hidden
| QDir::System
);
135 if(rootfolders
.contains("GBSYSTEM", Qt::CaseInsensitive
))
137 // GBSYSTEM folder -> Gigabeat
138 m_device
= "gigabeatf";
139 m_mountpoint
= mountpoints
.at(i
);
142 #if defined(Q_OS_WIN32)
143 // on windows, try to detect the drive letter of an Ipod
144 if(rootfolders
.contains("iPod_Control", Qt::CaseInsensitive
))
146 // iPod_Control folder -> Ipod found
147 // detecting of the Ipod type is done below using ipodpatcher
148 m_mountpoint
= mountpoints
.at(i
);
158 n
= ipod_scan(&ipod
);
160 qDebug() << "Ipod found:" << ipod
.modelstr
<< "at" << ipod
.diskname
;
161 m_device
= ipod
.targetname
;
162 m_mountpoint
= resolveMountPoint(ipod
.diskname
);
166 qDebug() << "ipodpatcher: no Ipod found." << n
;
170 struct sansa_t sansa
;
171 n
= sansa_scan(&sansa
);
173 qDebug() << "Sansa found:" << sansa
.targetname
<< "at" << sansa
.diskname
;
174 m_device
= QString("sansa%1").arg(sansa
.targetname
);
175 m_mountpoint
= resolveMountPoint(sansa
.diskname
);
179 qDebug() << "sansapatcher: no Sansa found." << n
;
182 if(m_mountpoint
.isEmpty() && m_device
.isEmpty() && m_errdev
.isEmpty() && m_incompat
.isEmpty())
188 QStringList
Autodetection::getMountpoints()
190 QStringList tempList
;
191 #if defined(Q_OS_WIN32)
192 QFileInfoList list
= QDir::drives();
193 for(int i
=0; i
<list
.size();i
++)
195 tempList
<< list
.at(i
).absolutePath();
198 #elif defined(Q_OS_MACX)
200 struct statfs
*mntinf
;
202 num
= getmntinfo(&mntinf
, MNT_WAIT
);
204 tempList
<< QString(mntinf
->f_mntonname
);
207 #elif defined(Q_OS_LINUX)
209 FILE *mn
= setmntent("/etc/mtab", "r");
211 return QStringList("");
214 while((ent
= getmntent(mn
)))
215 tempList
<< QString(ent
->mnt_dir
);
219 #error Unknown Plattform
224 QString
Autodetection::resolveMountPoint(QString device
)
226 qDebug() << "Autodetection::resolveMountPoint(QString)" << device
;
228 #if defined(Q_OS_LINUX)
229 FILE *mn
= setmntent("/etc/mtab", "r");
234 while((ent
= getmntent(mn
))) {
235 if(QString(ent
->mnt_fsname
).startsWith(device
)
236 && QString(ent
->mnt_type
).contains("vfat", Qt::CaseInsensitive
)) {
238 return QString(ent
->mnt_dir
);
245 #if defined(Q_OS_MACX)
247 struct statfs
*mntinf
;
249 num
= getmntinfo(&mntinf
, MNT_WAIT
);
251 if(QString(mntinf
->f_mntfromname
).startsWith(device
)
252 && QString(mntinf
->f_fstypename
).contains("vfat", Qt::CaseInsensitive
))
253 return QString(mntinf
->f_mntonname
);
258 #if defined(Q_OS_WIN32)
260 unsigned int driveno
= device
.replace(QRegExp("^.*([0-9]+)"), "\\1").toInt();
262 for(int letter
= 'A'; letter
<= 'Z'; letter
++) {
265 TCHAR uncpath
[MAX_PATH
];
267 PVOLUME_DISK_EXTENTS extents
= (PVOLUME_DISK_EXTENTS
)buffer
;
269 _stprintf(uncpath
, _TEXT("\\\\.\\%c:"), letter
);
270 h
= CreateFile(uncpath
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
271 NULL
, OPEN_EXISTING
, 0, NULL
);
272 if(h
== INVALID_HANDLE_VALUE
) {
273 //qDebug() << "error getting extents for" << uncpath;
277 if(DeviceIoControl(h
, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
,
278 NULL
, 0, extents
, sizeof(buffer
), &written
, NULL
)) {
279 for(unsigned int a
= 0; a
< extents
->NumberOfDiskExtents
; a
++) {
280 qDebug() << "Disk:" << extents
->Extents
[a
].DiskNumber
;
281 if(extents
->Extents
[a
].DiskNumber
== driveno
) {
283 qDebug("drive found for volume %i: %c", driveno
, letter
);
291 return result
+ ":/";
297 /** @brief detect devices based on usb pid / vid.
298 * @return true upon success, false otherwise.
300 bool Autodetection::detectUsb()
302 // usbids holds the mapping in the form
303 // ((VID<<16)|(PID)), targetname
304 // the ini file needs to hold the IDs as hex values.
305 QMap
<int, QString
> usbids
= settings
->usbIdMap();
306 QMap
<int, QString
> usberror
= settings
->usbIdErrorMap();
307 QMap
<int, QString
> usbincompat
= settings
->usbIdIncompatMap();
310 QList
<uint32_t> attached
;
311 attached
= Detect::listUsbIds();
313 int i
= attached
.size();
315 if(usbids
.contains(attached
.at(i
))) {
316 m_device
= usbids
.value(attached
.at(i
));
317 qDebug() << "[USB] detected supported player" << m_device
;
320 if(usberror
.contains(attached
.at(i
))) {
321 m_errdev
= usberror
.value(attached
.at(i
));
322 qDebug() << "[USB] detected problem with player" << m_errdev
;
325 if(usbincompat
.contains(attached
.at(i
))) {
326 m_incompat
= usbincompat
.value(attached
.at(i
));
327 qDebug() << "[USB] detected incompatible player" << m_incompat
;
335 bool Autodetection::detectAjbrec(QString root
)
337 QFile
f(root
+ "/ajbrec.ajz");
339 f
.open(QIODevice::ReadOnly
);
340 if(!f
.read(header
, 24)) return false;
342 // check the header of the file.
343 // recorder v1 had a 6 bytes sized header
344 // recorder v2, FM, Ondio SP and FM have a 24 bytes header.
346 // recorder v1 has the binary length in the first 4 bytes, so check
348 int len
= (header
[0]<<24) | (header
[1]<<16) | (header
[2]<<8) | header
[3];
349 qDebug() << "possible bin length:" << len
;
350 qDebug() << "file len:" << f
.size();
351 if((f
.size() - 6) == len
)
352 m_device
= "recorder";
354 // size didn't match, now we need to assume we have a headerlength of 24.
357 m_device
= "recorderv2";
361 m_device
= "fmrecorder";
365 m_device
= "ondiofm";
369 m_device
= "ondiosp";
377 if(m_device
.isEmpty()) return false;