431cb0251e10cda2edf2700065ad0271c8d28740
[Rockbox.git] / rbutil / rbutilqt / autodetection.cpp
blob431cb0251e10cda2edf2700065ad0271c8d28740
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
9 * Copyright (C) 2007 by Dominik Wenger
10 * $Id$
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)
23 #include <stdio.h>
24 #include <usb.h>
25 #endif
26 #if defined(Q_OS_LINUX)
27 #include <mntent.h>
28 #endif
29 #if defined(Q_OS_MACX)
30 #include <sys/param.h>
31 #include <sys/ucred.h>
32 #include <sys/mount.h>
33 #endif
34 #if defined(Q_OS_WIN32)
35 #if defined(UNICODE)
36 #define _UNICODE
37 #endif
38 #include <stdio.h>
39 #include <tchar.h>
40 #include <windows.h>
41 #include <setupapi.h>
42 #endif
43 #include "detect.h"
45 Autodetection::Autodetection(QObject* parent): QObject(parent)
50 bool Autodetection::detect()
52 m_device = "";
53 m_mountpoint = "";
54 m_errdev = "";
56 detectUsb();
58 // Try detection via rockbox.info / rbutil.log
59 QStringList mountpoints = getMountpoints();
61 for(int i=0; i< mountpoints.size();i++)
63 // do the file checking
64 QDir dir(mountpoints.at(i));
65 if(dir.exists())
67 qDebug() << "file checking:" << mountpoints.at(i);
68 // check logfile first.
69 if(QFile(mountpoints.at(i) + "/.rockbox/rbutil.log").exists()) {
70 QSettings log(mountpoints.at(i) + "/.rockbox/rbutil.log",
71 QSettings::IniFormat, this);
72 if(!log.value("platform").toString().isEmpty()) {
73 if(m_device.isEmpty())
74 m_device = log.value("platform").toString();
75 m_mountpoint = mountpoints.at(i);
76 qDebug() << "rbutil.log detected:" << m_device << m_mountpoint;
77 return true;
81 // check rockbox-info.txt afterwards.
82 QFile file(mountpoints.at(i) + "/.rockbox/rockbox-info.txt");
83 if(file.exists())
85 file.open(QIODevice::ReadOnly | QIODevice::Text);
86 QString line = file.readLine();
87 if(line.startsWith("Target: "))
89 line.remove("Target: ");
90 if(m_device.isEmpty())
91 m_device = line.trimmed(); // trim whitespaces
92 m_mountpoint = mountpoints.at(i);
93 qDebug() << "rockbox-info.txt detected:" << m_device << m_mountpoint;
94 return true;
97 // check for some specific files in root folder
98 QDir root(mountpoints.at(i));
99 QStringList rootentries = root.entryList(QDir::Files);
100 if(rootentries.contains("archos.mod", Qt::CaseInsensitive))
102 // archos.mod in root folder -> Archos Player
103 m_device = "player";
104 m_mountpoint = mountpoints.at(i);
105 return true;
107 if(rootentries.contains("ONDIOST.BIN", Qt::CaseInsensitive))
109 // ONDIOST.BIN in root -> Ondio FM
110 m_device = "ondiofm";
111 m_mountpoint = mountpoints.at(i);
112 return true;
114 if(rootentries.contains("ONDIOSP.BIN", Qt::CaseInsensitive))
116 // ONDIOSP.BIN in root -> Ondio SP
117 m_device = "ondiosp";
118 m_mountpoint = mountpoints.at(i);
119 return true;
121 if(rootentries.contains("ajbrec.ajz", Qt::CaseInsensitive))
123 qDebug() << "ajbrec.ajz found. Trying detectAjbrec()";
124 if(detectAjbrec(mountpoints.at(i))) {
125 m_mountpoint = mountpoints.at(i);
126 qDebug() << m_device;
127 return true;
130 // detection based on player specific folders
131 QStringList rootfolders = root.entryList(QDir::Dirs
132 | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
133 if(rootfolders.contains("GBSYSTEM", Qt::CaseInsensitive))
135 // GBSYSTEM folder -> Gigabeat
136 m_device = "gigabeatf";
137 m_mountpoint = mountpoints.at(i);
138 return true;
140 #if defined(Q_OS_WIN32)
141 // on windows, try to detect the drive letter of an Ipod
142 if(rootfolders.contains("iPod_Control", Qt::CaseInsensitive))
144 // iPod_Control folder -> Ipod found
145 // detecting of the Ipod type is done below using ipodpatcher
146 m_mountpoint = mountpoints.at(i);
148 #endif
153 int n;
154 //try ipodpatcher
155 struct ipod_t ipod;
156 n = ipod_scan(&ipod);
157 if(n == 1) {
158 qDebug() << "Ipod found:" << ipod.modelstr << "at" << ipod.diskname;
159 m_device = ipod.targetname;
160 #if !defined(Q_OS_WIN32)
161 m_mountpoint = resolveMountPoint(ipod.diskname);
162 #endif
163 #if defined(Q_OS_WIN32)
164 m_mountpoint = getMountpointByDevice(ipod.diskname);
165 #endif
166 return true;
169 //try sansapatcher
170 struct sansa_t sansa;
171 n = sansa_scan(&sansa);
172 if(n == 1) {
173 qDebug() << "Sansa found:" << sansa.targetname << "at" << sansa.diskname;
174 m_device = QString("sansa%1").arg(sansa.targetname);
175 #if !defined(Q_OS_WIN32)
176 m_mountpoint = resolveMountPoint(sansa.diskname);
177 #endif
178 #if defined(Q_OS_WIN32)
179 m_mountpoint = getMountpointByDevice(sansa.diskname);
180 #endif
181 return true;
184 if(m_mountpoint.isEmpty() && m_device.isEmpty() && m_errdev.isEmpty() && m_incompat.isEmpty())
185 return false;
186 return true;
190 QStringList Autodetection::getMountpoints()
192 QStringList tempList;
193 #if defined(Q_OS_WIN32)
194 QFileInfoList list = QDir::drives();
195 for(int i=0; i<list.size();i++)
197 tempList << list.at(i).absolutePath();
200 #elif defined(Q_OS_MACX)
201 int num;
202 struct statfs *mntinf;
204 num = getmntinfo(&mntinf, MNT_WAIT);
205 while(num--) {
206 tempList << QString(mntinf->f_mntonname);
207 mntinf++;
209 #elif defined(Q_OS_LINUX)
211 FILE *mn = setmntent("/etc/mtab", "r");
212 if(!mn)
213 return QStringList("");
215 struct mntent *ent;
216 while((ent = getmntent(mn)))
217 tempList << QString(ent->mnt_dir);
218 endmntent(mn);
220 #else
221 #error Unknown Plattform
222 #endif
223 return tempList;
226 QString Autodetection::resolveMountPoint(QString device)
228 qDebug() << "Autodetection::resolveMountPoint(QString)" << device;
230 #if defined(Q_OS_LINUX)
231 FILE *mn = setmntent("/etc/mtab", "r");
232 if(!mn)
233 return QString("");
235 struct mntent *ent;
236 while((ent = getmntent(mn))) {
237 if(QString(ent->mnt_fsname).startsWith(device)
238 && QString(ent->mnt_type).contains("vfat", Qt::CaseInsensitive)) {
239 endmntent(mn);
240 return QString(ent->mnt_dir);
243 endmntent(mn);
245 #endif
247 #if defined(Q_OS_MACX)
248 int num;
249 struct statfs *mntinf;
251 num = getmntinfo(&mntinf, MNT_WAIT);
252 while(num--) {
253 if(QString(mntinf->f_mntfromname).startsWith(device)
254 && QString(mntinf->f_fstypename).contains("vfat", Qt::CaseInsensitive))
255 return QString(mntinf->f_mntonname);
256 mntinf++;
258 #endif
259 return QString("");
264 /** @brief detect devices based on usb pid / vid.
265 * @return true upon success, false otherwise.
267 bool Autodetection::detectUsb()
269 // usbids holds the mapping in the form
270 // ((VID<<16)|(PID)), targetname
271 // the ini file needs to hold the IDs as hex values.
272 QMap<int, QString> usbids = settings->usbIdMap();
273 QMap<int, QString> usberror = settings->usbIdErrorMap();
274 QMap<int, QString> usbincompat = settings->usbIdIncompatMap();
276 // usb pid detection
277 QList<uint32_t> attached;
278 attached = Detect::listUsbIds();
280 int i = attached.size();
281 while(i--) {
282 if(usbids.contains(attached.at(i))) {
283 m_device = usbids.value(attached.at(i));
284 qDebug() << "[USB] detected supported player" << m_device;
285 return true;
287 if(usberror.contains(attached.at(i))) {
288 m_errdev = usberror.value(attached.at(i));
289 qDebug() << "[USB] detected problem with player" << m_errdev;
290 return true;
292 if(usbincompat.contains(attached.at(i))) {
293 m_incompat = usbincompat.value(attached.at(i));
294 qDebug() << "[USB] detected incompatible player" << m_incompat;
295 return true;
298 return false;
302 bool Autodetection::detectAjbrec(QString root)
304 QFile f(root + "/ajbrec.ajz");
305 char header[24];
306 f.open(QIODevice::ReadOnly);
307 if(!f.read(header, 24)) return false;
309 // check the header of the file.
310 // recorder v1 had a 6 bytes sized header
311 // recorder v2, FM, Ondio SP and FM have a 24 bytes header.
313 // recorder v1 has the binary length in the first 4 bytes, so check
314 // for them first.
315 int len = (header[0]<<24) | (header[1]<<16) | (header[2]<<8) | header[3];
316 qDebug() << "possible bin length:" << len;
317 qDebug() << "file len:" << f.size();
318 if((f.size() - 6) == len)
319 m_device = "recorder";
321 // size didn't match, now we need to assume we have a headerlength of 24.
322 switch(header[11]) {
323 case 2:
324 m_device = "recorderv2";
325 break;
327 case 4:
328 m_device = "fmrecorder";
329 break;
331 case 8:
332 m_device = "ondiofm";
333 break;
335 case 16:
336 m_device = "ondiosp";
337 break;
339 default:
340 break;
342 f.close();
344 if(m_device.isEmpty()) return false;
345 return true;