~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kinfocenter/Modules/usbview/usbdevices.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2001 by Matthias Hoelzer-Kluepfel <mhk@caldera.de>      *
 
3
 *                                                                         *
 
4
 *   This program is free software; you can redistribute it and/or modify  *
 
5
 *   it under the terms of the GNU General Public License as published by  *
 
6
 *   the Free Software Foundation; either version 2 of the License, or     *
 
7
 *   (at your option) any later version.                                   *
 
8
 *                                                                         *
 
9
 ***************************************************************************/
 
10
 
 
11
#include "usbdevices.h"
 
12
 
 
13
#include <sys/types.h>
 
14
#include <sys/stat.h>
 
15
#include <fcntl.h>
 
16
#include <unistd.h>
 
17
#include <stdio.h>
 
18
 
 
19
#include <QFile>
 
20
#include <QDir>
 
21
#include <QRegExp>
 
22
 
 
23
#include <klocale.h>
 
24
#include <kmessagebox.h>
 
25
 
 
26
#include "usbdb.h"
 
27
 
 
28
#include <math.h>
 
29
 
 
30
#if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
 
31
#include <sys/ioctl.h>
 
32
#include <sys/param.h>
 
33
#endif
 
34
 
 
35
QList<USBDevice*> USBDevice::_devices;
 
36
USBDB *USBDevice::_db;
 
37
 
 
38
USBDevice::USBDevice() :
 
39
        _bus(0), _level(0), _parent(0), _port(0), _count(0), _device(0), _channels(0), _power(0), _speed(0.0), _bwTotal(0), _bwUsed(0), _bwPercent(0), _bwIntr(0), _bwIso(0), _hasBW(false), _verMajor(0), _verMinor(0), _class(0), _sub(0), _prot(0), _maxPacketSize(0), _configs(0), _vendorID(0),
 
40
                        _prodID(0), _revMajor(0), _revMinor(0) {
 
41
        _devices.append(this);
 
42
 
 
43
        if (!_db)
 
44
                _db = new USBDB;
 
45
}
 
46
 
 
47
USBDevice::~USBDevice() {
 
48
 
 
49
}
 
50
 
 
51
static QString catFile(QString fname) {
 
52
        char buffer[256];
 
53
        QString result;
 
54
        int fd =:: open(QFile::encodeName(fname), O_RDONLY);
 
55
        if (fd<0)
 
56
        return QString();
 
57
 
 
58
        if (fd >= 0)
 
59
        {
 
60
                ssize_t count;
 
61
                while ((count = ::read(fd, buffer, 256)) > 0)
 
62
                result.append(QString(buffer).left(count));
 
63
 
 
64
                ::close(fd);
 
65
        }
 
66
        return result.trimmed();
 
67
}
 
68
 
 
69
void USBDevice::parseSysDir(int bus, int parent, int level, const QString& dname) {
 
70
        _level = level;
 
71
        _parent = parent;
 
72
        _manufacturer = catFile(dname + "/manufacturer");
 
73
        _product = catFile(dname + "/product");
 
74
 
 
75
        _bus = bus;
 
76
        _device = catFile(dname + "/devnum").toUInt();
 
77
 
 
78
        if (_device == 1)
 
79
                _product += QString(" (%1)").arg(_bus);
 
80
 
 
81
        _vendorID = catFile(dname + "/idVendor").toUInt(0, 16);
 
82
        _prodID = catFile(dname + "/idProduct").toUInt(0, 16);
 
83
 
 
84
        _class = catFile(dname + "/bDeviceClass").toUInt(0, 16);
 
85
        _sub = catFile(dname + "/bDeviceSubClass").toUInt(0, 16);
 
86
        _maxPacketSize = catFile(dname + "/bMaxPacketSize0").toUInt();
 
87
 
 
88
        _speed = catFile(dname + "/speed").toDouble();
 
89
        _serial = catFile(dname + "/serial");
 
90
        _channels = catFile(dname + "/maxchild").toUInt();
 
91
 
 
92
        double version = catFile(dname + "/version").toDouble();
 
93
        _verMajor = int(version);
 
94
        _verMinor = int(10*(version - floor(version)));
 
95
 
 
96
        QDir dir(dname);
 
97
        dir.setNameFilters(QStringList() << QString("%1-*").arg(bus));
 
98
        dir.setFilter(QDir::Dirs);
 
99
        const QStringList list = dir.entryList();
 
100
 
 
101
        for (QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it) {
 
102
                if ((*it).contains(':'))
 
103
                        continue;
 
104
 
 
105
                USBDevice* dev = new USBDevice();
 
106
                dev->parseSysDir(bus, ++level, _device, dname + '/' + *it);
 
107
        }
 
108
}
 
109
 
 
110
void USBDevice::parseLine(const QString& line) {
 
111
        if (line.startsWith("T:"))
 
112
                sscanf(line.toLocal8Bit().data(), "T:  Bus=%2d Lev=%2d Prnt=%2d Port=%d Cnt=%2d Dev#=%3d Spd=%3f MxCh=%2d", &_bus, &_level, &_parent, &_port, &_count, &_device, &_speed, &_channels);
 
113
        else if (line.startsWith("S:  Manufacturer"))
 
114
                _manufacturer = line.mid(17);
 
115
        else if (line.startsWith("S:  Product")) {
 
116
                _product = line.mid(12);
 
117
                /* add bus number to root devices */
 
118
                if (_device==1)
 
119
                        _product += QString(" (%1)").arg(_bus);
 
120
        } else if (line.startsWith("S:  SerialNumber"))
 
121
                _serial = line.mid(17);
 
122
        else if (line.startsWith("B:")) {
 
123
                sscanf(line.toLocal8Bit().data(), "B:  Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d", &_bwUsed, &_bwTotal, &_bwPercent, &_bwIntr, &_bwIso);
 
124
                _hasBW = true;
 
125
        } else if (line.startsWith("D:")) {
 
126
                char buffer[11];
 
127
                sscanf(line.toLocal8Bit().data(), "D:  Ver=%x.%x Cls=%x(%10s) Sub=%x Prot=%x MxPS=%u #Cfgs=%u", &_verMajor, &_verMinor, &_class, buffer, &_sub, &_prot, &_maxPacketSize, &_configs);
 
128
                _className = buffer;
 
129
        } else if (line.startsWith("P:"))
 
130
                sscanf(line.toLocal8Bit().data(), "P:  Vendor=%x ProdID=%x Rev=%x.%x", &_vendorID, &_prodID, &_revMajor, &_revMinor);
 
131
}
 
132
 
 
133
USBDevice* USBDevice::find(int bus, int device) {
 
134
        foreach(USBDevice* usbDevice, _devices) {
 
135
                if (usbDevice->bus() == bus && usbDevice->device() == device)
 
136
                        return usbDevice;
 
137
        }
 
138
 
 
139
        return NULL;
 
140
}
 
141
 
 
142
QString USBDevice::product() {
 
143
        if (!_product.isEmpty())
 
144
                return _product;
 
145
        QString pname = _db->device(_vendorID, _prodID);
 
146
        if (!pname.isEmpty())
 
147
                return pname;
 
148
        return i18n("Unknown");
 
149
}
 
150
 
 
151
QString USBDevice::dump() {
 
152
        QString r;
 
153
 
 
154
        r = "<qml><h2><center>" + product() + "</center></h2><br/><hl/>";
 
155
 
 
156
        if (!_manufacturer.isEmpty())
 
157
                r += i18n("<b>Manufacturer:</b> ") + _manufacturer + "<br/>";
 
158
        if (!_serial.isEmpty())
 
159
                r += i18n("<b>Serial #:</b> ") + _serial + "<br/>";
 
160
 
 
161
        r += "<br/><table>";
 
162
 
 
163
        QString c = QString("<td>%1</td>").arg(_class);
 
164
        QString cname = _db->cls(_class);
 
165
        if (!cname.isEmpty())
 
166
                c += "<td>(" + i18n(cname.toLatin1()) +")</td>";
 
167
        r += i18n("<tr><td><i>Class</i></td>%1</tr>", c);
 
168
        QString sc = QString("<td>%1</td>").arg(_sub);
 
169
        QString scname = _db->subclass(_class, _sub);
 
170
        if (!scname.isEmpty())
 
171
                sc += "<td>(" + i18n(scname.toLatin1()) +")</td>";
 
172
        r += i18n("<tr><td><i>Subclass</i></td>%1</tr>", sc);
 
173
        QString pr = QString("<td>%1</td>").arg(_prot);
 
174
        QString prname = _db->protocol(_class, _sub, _prot);
 
175
        if (!prname.isEmpty())
 
176
                pr += "<td>(" + prname +")</td>";
 
177
        r += i18n("<tr><td><i>Protocol</i></td>%1</tr>", pr);
 
178
#if !(defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD))
 
179
        r += ki18n("<tr><td><i>USB Version</i></td><td>%1.%2</td></tr>")
 
180
        .subs(_verMajor,0,16).subs(_verMinor,2,16,QChar::fromLatin1('0'))
 
181
        .toString();
 
182
#endif
 
183
        r += "<tr><td></td></tr>";
 
184
 
 
185
        QString v = QString::number(_vendorID, 16);
 
186
        QString name = _db->vendor(_vendorID);
 
187
        if (!name.isEmpty())
 
188
                v += "<td>(" + name +")</td>";
 
189
        r += i18n("<tr><td><i>Vendor ID</i></td><td>0x%1</td></tr>", v);
 
190
        QString p = QString::number(_prodID, 16);
 
191
        QString pname = _db->device(_vendorID, _prodID);
 
192
        if (!pname.isEmpty())
 
193
                p += "<td>(" + pname +")</td>";
 
194
        r += i18n("<tr><td><i>Product ID</i></td><td>0x%1</td></tr>", p);
 
195
        r += ki18n("<tr><td><i>Revision</i></td><td>%1.%2</td></tr>")
 
196
        .subs(_revMajor,0,16).subs(_revMinor,2,16,QChar::fromLatin1('0'))
 
197
        .toString();
 
198
        r += "<tr><td></td></tr>";
 
199
 
 
200
        r += i18n("<tr><td><i>Speed</i></td><td>%1 Mbit/s</td></tr>", _speed);
 
201
        r += i18n("<tr><td><i>Channels</i></td><td>%1</td></tr>", _channels);
 
202
#if (defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)) && !defined(DISABLE_USBDEVICES_FREEBSD)
 
203
        if ( _power )
 
204
        r += i18n("<tr><td><i>Power Consumption</i></td><td>%1 mA</td></tr>", _power);
 
205
        else
 
206
        r += i18n("<tr><td><i>Power Consumption</i></td><td>self powered</td></tr>");
 
207
        r += i18n("<tr><td><i>Attached Devicenodes</i></td><td>%1</td></tr>", _devnodes.at(0));
 
208
        if ( _devnodes.count() > 1 ) {
 
209
                QStringList::const_iterator it = _devnodes.constBegin();
 
210
                ++it;
 
211
                for (; it != _devnodes.constEnd(); ++it )
 
212
                r += "<tr><td></td><td>" + *it + "</td></tr>";
 
213
        }
 
214
#else
 
215
        r += i18n("<tr><td><i>Max. Packet Size</i></td><td>%1</td></tr>", _maxPacketSize);
 
216
#endif
 
217
        r += "<tr><td></td></tr>";
 
218
 
 
219
        if (_hasBW) {
 
220
                r += i18n("<tr><td><i>Bandwidth</i></td><td>%1 of %2 (%3%)</td></tr>", _bwUsed, _bwTotal, _bwPercent);
 
221
                r += i18n("<tr><td><i>Intr. requests</i></td><td>%1</td></tr>", _bwIntr);
 
222
                r += i18n("<tr><td><i>Isochr. requests</i></td><td>%1</td></tr>", _bwIso);
 
223
                r += "<tr><td></td></tr>";
 
224
        }
 
225
 
 
226
        r += "</table>";
 
227
 
 
228
        return r;
 
229
}
 
230
 
 
231
#if !(defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD))
 
232
bool USBDevice::parse(const QString &fname) {
 
233
        _devices.clear();
 
234
 
 
235
        QString result;
 
236
 
 
237
        // read in the complete file
 
238
        //
 
239
        // Note: we can't use a QTextStream, as the files in /proc
 
240
        // are pseudo files with zero length
 
241
        char buffer[256];
 
242
        int fd =:: open(QFile::encodeName(fname), O_RDONLY);
 
243
        if (fd<0)
 
244
        return false;
 
245
 
 
246
        if (fd >= 0)
 
247
        {
 
248
                ssize_t count;
 
249
                while ((count = ::read(fd, buffer, 256)) > 0)
 
250
                result.append(QString(buffer).left(count));
 
251
 
 
252
                ::close(fd);
 
253
        }
 
254
 
 
255
        // read in the device infos
 
256
        USBDevice *device = 0;
 
257
        int start=0, end;
 
258
        result.replace(QRegExp("^\n"),"");
 
259
        while ((end = result.indexOf('\n', start)) > 0)
 
260
        {
 
261
                QString line = result.mid(start, end-start);
 
262
 
 
263
                if (line.startsWith("T:"))
 
264
                device = new USBDevice();
 
265
 
 
266
                if (device)
 
267
                device->parseLine(line);
 
268
 
 
269
                start = end+1;
 
270
        }
 
271
        return true;
 
272
}
 
273
 
 
274
bool USBDevice::parseSys(const QString &dname) {
 
275
        QDir d(dname);
 
276
        d.setNameFilters(QStringList() << "usb*");
 
277
        const QStringList list = d.entryList();
 
278
 
 
279
        for (QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it) {
 
280
                USBDevice* device = new USBDevice();
 
281
 
 
282
                int bus = 0;
 
283
                QRegExp bus_reg("[a-z]*([0-9]+)");
 
284
                if (bus_reg.indexIn(*it) != -1)
 
285
                        bus = bus_reg.cap(1).toInt();
 
286
 
 
287
                device->parseSysDir(bus, 0, 0, d.absolutePath() + '/' + *it);
 
288
        }
 
289
 
 
290
        return d.count();
 
291
}
 
292
 
 
293
#else
 
294
 
 
295
// Unused by *BSD
 
296
bool USBDevice::parseSys(const QString &fname)
 
297
{
 
298
        Q_UNUSED(fname)
 
299
 
 
300
        return true;
 
301
}
 
302
 
 
303
# if defined(DISABLE_USBDEVICES_FREEBSD)
 
304
 
 
305
/*
 
306
 * FIXME: The USB subsystem has changed a lot in FreeBSD 8.0
 
307
 *        Support for it must be written.
 
308
 */
 
309
 
 
310
bool USBDevice::parse(const QString &fname)
 
311
{
 
312
        Q_UNUSED(fname)
 
313
 
 
314
        return true;
 
315
}
 
316
 
 
317
# else
 
318
 
 
319
/*
 
320
 * FreeBSD support by Markus Brueffer <markus@brueffer.de>
 
321
 *
 
322
 * Basic idea and some code fragments were taken from FreeBSD's usbdevs(8),
 
323
 * originally developed for NetBSD, so this code should work with no or
 
324
 * only little modification on NetBSD.
 
325
 */
 
326
 
 
327
void USBDevice::collectData( int fd, int level, usb_device_info &di, int parent)
 
328
{
 
329
        // determine data for this device
 
330
        _level = level;
 
331
        _parent = parent;
 
332
 
 
333
        _bus = di.udi_bus;
 
334
        _device = di.udi_addr;
 
335
        _product = QLatin1String(di.udi_product);
 
336
        if ( _device == 1 )
 
337
        _product += ' ' + QString::number( _bus );
 
338
        _manufacturer = QLatin1String(di.udi_vendor);
 
339
        _prodID = di.udi_productNo;
 
340
        _vendorID = di.udi_vendorNo;
 
341
        _class = di.udi_class;
 
342
        _sub = di.udi_subclass;
 
343
        _prot = di.udi_protocol;
 
344
        _power = di.udi_power;
 
345
        _channels = di.udi_nports;
 
346
 
 
347
        // determine the speed
 
348
#if defined(__DragonFly__) || (defined(Q_OS_FREEBSD) && __FreeBSD_version > 490102) || defined(Q_OS_NETBSD)
 
349
        switch (di.udi_speed) {
 
350
                case USB_SPEED_LOW: _speed = 1.5; break;
 
351
                case USB_SPEED_FULL: _speed = 12.0; break;
 
352
                case USB_SPEED_HIGH: _speed = 480.0; break;
 
353
        }
 
354
#else
 
355
        _speed = di.udi_lowspeed ? 1.5 : 12.0;
 
356
#endif
 
357
 
 
358
        // Get all attached devicenodes
 
359
        for ( int i = 0; i < USB_MAX_DEVNAMES; ++i )
 
360
        if ( di.udi_devnames[i][0] )
 
361
        _devnodes << di.udi_devnames[i];
 
362
 
 
363
        // For compatibility, split the revision number
 
364
        sscanf( di.udi_release, "%x.%x", &_revMajor, &_revMinor );
 
365
 
 
366
        // Cycle through the attached devices if there are any
 
367
        for ( int p = 0; p < di.udi_nports; ++p ) {
 
368
                // Get data for device
 
369
                struct usb_device_info di2;
 
370
 
 
371
                di2.udi_addr = di.udi_ports[p];
 
372
 
 
373
                if ( di2.udi_addr >= USB_MAX_DEVICES )
 
374
                continue;
 
375
 
 
376
                if ( ioctl(fd, USB_DEVICEINFO, &di2) == -1 )
 
377
                continue;
 
378
 
 
379
                // Only add the device if we didn't detect it, yet
 
380
                if (!find( di2.udi_bus, di2.udi_addr ) )
 
381
                {
 
382
                        USBDevice *device = new USBDevice();
 
383
                        device->collectData( fd, level + 1, di2, di.udi_addr );
 
384
                }
 
385
        }
 
386
}
 
387
 
 
388
bool USBDevice::parse(const QString &fname)
 
389
{
 
390
        Q_UNUSED(fname)
 
391
 
 
392
        static bool showErrorMessage = true;
 
393
        bool error = false;
 
394
        _devices.clear();
 
395
 
 
396
        QFile controller("/dev/usb0");
 
397
        int i = 1;
 
398
        while ( controller.exists() )
 
399
        {
 
400
                // If the devicenode exists, continue with further inspection
 
401
                if ( controller.open(QIODevice::ReadOnly) )
 
402
                {
 
403
                        for ( int addr = 1; addr < USB_MAX_DEVICES; ++addr )
 
404
                        {
 
405
                                struct usb_device_info di;
 
406
 
 
407
                                di.udi_addr = addr;
 
408
                                if ( ioctl(controller.handle(), USB_DEVICEINFO, &di) != -1 )
 
409
                                {
 
410
                                        if (!find( di.udi_bus, di.udi_addr ) )
 
411
                                        {
 
412
                                                USBDevice *device = new USBDevice();
 
413
                                                device->collectData( controller.handle(), 0, di, 0);
 
414
                                        }
 
415
                                }
 
416
                        }
 
417
                        controller.close();
 
418
#ifndef Q_OS_NETBSD
 
419
                } else {
 
420
                        error = true;
 
421
#endif
 
422
                }
 
423
                controller.setFileName( QString::fromLocal8Bit("/dev/usb%1").arg(i++) );
 
424
        }
 
425
 
 
426
        if ( showErrorMessage && error ) {
 
427
                showErrorMessage = false;
 
428
                KMessageBox::error( 0, i18n("Could not open one or more USB controller. Make sure, you have read access to all USB controllers that should be listed here."));
 
429
        }
 
430
 
 
431
        return true;
 
432
}
 
433
 
 
434
# endif // defined(DISABLE_USBDEVICES_FREEBSD)
 
435
#endif // !(defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD))