Introduce Rockbox Utility to the manual as automated installation option. Only rather...
[Rockbox.git] / rbutil / rbutilqt / autodetection.cpp
blobdef1d12ef76dd3ee36e05f6f8c9e0d4b05e8c349
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 <mntent.h>
25 #include <usb.h>
26 #endif
27 #if defined(Q_OS_WIN32)
28 #if defined(UNICODE)
29 #define _UNICODE
30 #endif
31 #include <stdio.h>
32 #include <tchar.h>
33 #include <windows.h>
34 #include <setupapi.h>
35 #endif
37 Autodetection::Autodetection(QObject* parent): QObject(parent)
42 bool Autodetection::detect()
44 m_device = "";
45 m_mountpoint = "";
46 m_errdev = "";
48 detectUsb();
50 // Try detection via rockbox.info / rbutil.log
51 QStringList mountpoints = getMountpoints();
53 for(int i=0; i< mountpoints.size();i++)
55 // do the file checking
56 QDir dir(mountpoints.at(i));
57 if(dir.exists())
59 // check logfile first.
60 if(QFile(mountpoints.at(i) + "/.rockbox/rbutil.log").exists()) {
61 QSettings log(mountpoints.at(i) + "/.rockbox/rbutil.log",
62 QSettings::IniFormat, this);
63 if(!log.value("platform").toString().isEmpty()) {
64 if(m_device.isEmpty())
65 m_device = log.value("platform").toString();
66 m_mountpoint = mountpoints.at(i);
67 qDebug() << "rbutil.log detected:" << m_device << m_mountpoint;
68 return true;
72 // check rockbox-info.txt afterwards.
73 QFile file(mountpoints.at(i) + "/.rockbox/rockbox-info.txt");
74 if(file.exists())
76 file.open(QIODevice::ReadOnly | QIODevice::Text);
77 QString line = file.readLine();
78 if(line.startsWith("Target: "))
80 line.remove("Target: ");
81 if(m_device.isEmpty())
82 m_device = line.trimmed(); // trim whitespaces
83 m_mountpoint = mountpoints.at(i);
84 qDebug() << "rockbox-info.txt detected:" << m_device << m_mountpoint;
85 return true;
88 // check for some specific files in root folder
89 QDir root(mountpoints.at(i));
90 QStringList rootentries = root.entryList(QDir::Files);
91 if(rootentries.contains("archos.mod", Qt::CaseInsensitive))
93 // archos.mod in root folder -> Archos Player
94 m_device = "player";
95 m_mountpoint = mountpoints.at(i);
96 return true;
98 if(rootentries.contains("ONDIOST.BIN"), Qt::CaseInsensitive)
100 // ONDIOST.BIN in root -> Ondio FM
101 m_device = "ondiofm";
102 m_mountpoint = mountpoints.at(i);
103 return true;
105 if(rootentries.contains("ONDIOSP.BIN"), Qt::CaseInsensitive)
107 // ONDIOSP.BIN in root -> Ondio SP
108 m_device = "ondiosp";
109 m_mountpoint = mountpoints.at(i);
110 return true;
112 if(rootentries.contains("ajbrec.ajz"), Qt::CaseInsensitive)
114 qDebug() << "it's an archos. further detection needed";
116 // detection based on player specific folders
117 QStringList rootfolders = root.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
118 if(rootfolders.contains("GBSYSTEM"), Qt::CaseInsensitive)
120 // GBSYSTEM folder -> Gigabeat
121 m_device = "gigabeatf";
122 m_mountpoint = mountpoints.at(i);
123 return true;
125 qDebug() << rootfolders;
130 int n;
131 //try ipodpatcher
132 struct ipod_t ipod;
133 n = ipod_scan(&ipod);
134 if(n == 1) {
135 qDebug() << "Ipod found:" << ipod.modelstr << "at" << ipod.diskname;
136 m_device = ipod.targetname;
137 m_mountpoint = resolveMountPoint(ipod.diskname);
138 return true;
141 //try sansapatcher
142 struct sansa_t sansa;
143 n = sansa_scan(&sansa);
144 if(n == 1) {
145 qDebug() << "Sansa found:" << sansa.targetname << "at" << sansa.diskname;
146 m_device = QString("sansa%1").arg(sansa.targetname);
147 m_mountpoint = resolveMountPoint(sansa.diskname);
148 return true;
151 if(m_mountpoint.isEmpty() && m_device.isEmpty() && m_errdev.isEmpty())
152 return false;
153 return true;
157 QStringList Autodetection::getMountpoints()
159 #if defined(Q_OS_WIN32)
160 QStringList tempList;
161 QFileInfoList list = QDir::drives();
162 for(int i=0; i<list.size();i++)
164 tempList << list.at(i).absolutePath();
166 return tempList;
168 #elif defined(Q_OS_MACX)
169 QDir dir("/Volumes");
170 return dir.entryList();
171 #elif defined(Q_OS_LINUX)
172 QStringList tempList;
174 FILE *mn = setmntent("/etc/mtab", "r");
175 if(!mn)
176 return QStringList("");
178 struct mntent *ent;
179 while((ent = getmntent(mn)))
180 tempList << QString(ent->mnt_dir);
181 endmntent(mn);
183 return tempList;
184 #else
185 #error Unknown Plattform
186 #endif
189 QString Autodetection::resolveMountPoint(QString device)
191 qDebug() << "Autodetection::resolveMountPoint(QString)" << device;
193 #if defined(Q_OS_LINUX)
194 FILE *mn = setmntent("/etc/mtab", "r");
195 if(!mn)
196 return QString("");
198 struct mntent *ent;
199 while((ent = getmntent(mn))) {
200 if(QString(ent->mnt_fsname).startsWith(device)
201 && QString(ent->mnt_type).contains("vfat", Qt::CaseInsensitive)) {
202 endmntent(mn);
203 return QString(ent->mnt_dir);
206 endmntent(mn);
208 #endif
209 return QString("");
214 /** @brief detect devices based on usb pid / vid.
215 * @return true upon success, false otherwise.
217 bool Autodetection::detectUsb()
219 // autodetection uses the buildin device settings only
220 QSettings dev(":/ini/rbutil.ini", QSettings::IniFormat, this);
222 // get a list of ID -> target name
223 QStringList platforms;
224 dev.beginGroup("platforms");
225 platforms = dev.childKeys();
226 dev.endGroup();
228 // usbids holds the mapping in the form
229 // ((VID<<16)|(PID)), targetname
230 // the ini file needs to hold the IDs as hex values.
231 QMap<int, QString> usbids;
232 QMap<int, QString> usberror;
234 for(int i = 0; i < platforms.size(); i++) {
235 dev.beginGroup("platforms");
236 QString target = dev.value(platforms.at(i)).toString();
237 dev.endGroup();
238 dev.beginGroup(target);
239 if(!dev.value("usbid").toString().isEmpty())
240 usbids.insert(dev.value("usbid").toString().toInt(0, 16), target);
241 if(!dev.value("usberror").toString().isEmpty())
242 usberror.insert(dev.value("usberror").toString().toInt(0, 16), target);
243 dev.endGroup();
246 // usb pid detection
247 #if defined(Q_OS_LINUX) | defined(Q_OS_MACX)
248 usb_init();
249 usb_find_busses();
250 usb_find_devices();
251 struct usb_bus *b;
252 b = usb_get_busses();
254 while(b) {
255 qDebug() << "bus:" << b->dirname << b->devices;
256 if(b->devices) {
257 qDebug() << "devices present.";
258 struct usb_device *u;
259 u = b->devices;
260 while(u) {
261 uint32_t id;
262 id = u->descriptor.idVendor << 16 | u->descriptor.idProduct;
263 qDebug("%x", id);
265 if(usbids.contains(id)) {
266 m_device = usbids.value(id);
267 return true;
269 if(usberror.contains(id)) {
270 m_errdev = usberror.value(id);
271 // we detected something, so return true
272 qDebug() << "detected device with problems via usb!";
273 return true;
275 u = u->next;
278 b = b->next;
280 #endif
282 #if defined(Q_OS_WIN32)
283 HDEVINFO deviceInfo;
284 SP_DEVINFO_DATA infoData;
285 DWORD i;
287 // Iterate over all devices
288 // by doing it this way it's unneccessary to use GUIDs which might be not
289 // present in current MinGW. It also seemed to be more reliably than using
290 // a GUID.
291 // See KB259695 for an example.
292 deviceInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
294 infoData.cbSize = sizeof(SP_DEVINFO_DATA);
296 for(i = 0; SetupDiEnumDeviceInfo(deviceInfo, i, &infoData); i++) {
297 DWORD data;
298 LPTSTR buffer = NULL;
299 DWORD buffersize = 0;
301 // get device desriptor first
302 // for some reason not doing so results in bad things (tm)
303 while(!SetupDiGetDeviceRegistryProperty(deviceInfo, &infoData,
304 SPDRP_DEVICEDESC,&data, (PBYTE)buffer, buffersize, &buffersize)) {
305 if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
306 if(buffer) free(buffer);
307 // double buffer size to avoid problems as per KB888609
308 buffer = (LPTSTR)malloc(buffersize * 2);
310 else {
311 break;
315 // now get the hardware id, which contains PID and VID.
316 while(!SetupDiGetDeviceRegistryProperty(deviceInfo, &infoData,
317 SPDRP_HARDWAREID,&data, (PBYTE)buffer, buffersize, &buffersize)) {
318 if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
319 if(buffer) free(buffer);
320 // double buffer size to avoid problems as per KB888609
321 buffer = (LPTSTR)malloc(buffersize * 2);
323 else {
324 break;
328 unsigned int vid, pid, rev;
329 if(_stscanf(buffer, _TEXT("USB\\Vid_%x&Pid_%x&Rev_%x"), &vid, &pid, &rev) != 3) {
330 qDebug() << "Error getting USB ID -- possibly no USB device";
332 else {
333 uint32_t id;
334 id = vid << 16 | pid;
335 qDebug("VID: %04x PID: %04x", vid, pid);
336 if(usbids.contains(id)) {
337 m_device = usbids.value(id);
338 if(buffer) free(buffer);
339 SetupDiDestroyDeviceInfoList(deviceInfo);
340 qDebug() << "detectUsb: Got" << m_device;
341 return true;
343 if(usberror.contains(id)) {
344 m_errdev = usberror.value(id);
345 // we detected something, so return true
346 if(buffer) free(buffer);
347 SetupDiDestroyDeviceInfoList(deviceInfo);
348 qDebug() << "detectUsb: Got" << m_device;
349 qDebug() << "detected device with problems via usb!";
350 return true;
353 if(buffer) free(buffer);
355 SetupDiDestroyDeviceInfoList(deviceInfo);
357 #endif
358 return false;