diff --git a/Modules/usbview/usbdevices.cpp b/Modules/usbview/usbdevices.cpp index 7b6fe1c..b950f97 100644 --- a/Modules/usbview/usbdevices.cpp +++ b/Modules/usbview/usbdevices.cpp @@ -1,435 +1,434 @@ /*************************************************************************** * Copyright (C) 2001 by Matthias Hoelzer-Kluepfel * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "usbdevices.h" #include #include #include #include #include #include #include #include #include #include #include "usbdb.h" #include #if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) #include #include #endif QList USBDevice::_devices; USBDB *USBDevice::_db; USBDevice::USBDevice() : _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), _prodID(0), _revMajor(0), _revMinor(0) { _devices.append(this); if (!_db) _db = new USBDB; } USBDevice::~USBDevice() { } static QString catFile(const QString &fname) { char buffer[256]; QString result; int fd =:: open(QFile::encodeName(fname).constData(), O_RDONLY); if (fd<0) return QString(); if (fd >= 0) { ssize_t count; while ((count = ::read(fd, buffer, 256)) > 0) result.append(QString::fromLatin1(buffer).leftRef(count)); ::close(fd); } return result.trimmed(); } void USBDevice::parseSysDir(int bus, int parent, int level, const QString& dname) { _level = level; _parent = parent; _manufacturer = catFile(dname + QStringLiteral("/manufacturer")); _product = catFile(dname + QStringLiteral("/product")); _bus = bus; _device = catFile(dname + QStringLiteral("/devnum")).toUInt(); if (_device == 1) _product += QStringLiteral(" (%1)").arg(_bus); _vendorID = catFile(dname + QStringLiteral("/idVendor")).toUInt(nullptr, 16); _prodID = catFile(dname + QStringLiteral("/idProduct")).toUInt(nullptr, 16); _class = catFile(dname + QStringLiteral("/bDeviceClass")).toUInt(nullptr, 16); _sub = catFile(dname + QStringLiteral("/bDeviceSubClass")).toUInt(nullptr, 16); _maxPacketSize = catFile(dname + QStringLiteral("/bMaxPacketSize0")).toUInt(); _speed = catFile(dname + QStringLiteral("/speed")).toDouble(); _serial = catFile(dname + QStringLiteral("/serial")); _channels = catFile(dname + QStringLiteral("/maxchild")).toUInt(); - double version = catFile(dname + QStringLiteral("/version")).toDouble(); - _verMajor = int(version); - _verMinor = int(10*(version - floor(version))); + const QString version = catFile(dname + QStringLiteral("/version")); + sscanf(qPrintable(version), "%2x.%02x", &_verMajor, &_verMinor); QDir dir(dname); dir.setNameFilters(QStringList() << QStringLiteral("%1-*").arg(bus)); dir.setFilter(QDir::Dirs); const QStringList list = dir.entryList(); for (QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it) { if ((*it).contains(QLatin1Char(':'))) continue; USBDevice* dev = new USBDevice(); dev->parseSysDir(bus, _device, ++level, dname + QLatin1Char('/') + *it); } } void USBDevice::parseLine(const QString& line) { if (line.startsWith(QLatin1String("T:"))) 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); else if (line.startsWith(QLatin1String("S: Manufacturer"))) _manufacturer = line.mid(17); else if (line.startsWith(QLatin1String("S: Product"))) { _product = line.mid(12); /* add bus number to root devices */ if (_device==1) _product += QStringLiteral(" (%1)").arg(_bus); } else if (line.startsWith(QLatin1String("S: SerialNumber"))) _serial = line.mid(17); else if (line.startsWith(QLatin1String("B:"))) { sscanf(line.toLocal8Bit().data(), "B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d", &_bwUsed, &_bwTotal, &_bwPercent, &_bwIntr, &_bwIso); _hasBW = true; } else if (line.startsWith(QLatin1String("D:"))) { char buffer[11]; 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); _className = QString::fromLatin1(buffer); } else if (line.startsWith(QLatin1String("P:"))) sscanf(line.toLocal8Bit().data(), "P: Vendor=%x ProdID=%x Rev=%x.%x", &_vendorID, &_prodID, &_revMajor, &_revMinor); } USBDevice* USBDevice::find(int bus, int device) { foreach(USBDevice* usbDevice, _devices) { if (usbDevice->bus() == bus && usbDevice->device() == device) return usbDevice; } return nullptr; } QString USBDevice::product() { if (!_product.isEmpty()) return _product; QString pname = _db->device(_vendorID, _prodID); if (!pname.isEmpty()) return pname; return i18n("Unknown"); } QString USBDevice::dump() { QString r; r = QStringLiteral("

") + product() + QStringLiteral("


"); if (!_manufacturer.isEmpty()) r += i18n("Manufacturer: ") + _manufacturer + QStringLiteral("
"); if (!_serial.isEmpty()) r += i18n("Serial #: ") + _serial + QStringLiteral("
"); r += QLatin1String("
"); QString c = QStringLiteral("").arg(_class); QString cname = _db->cls(_class); if (!cname.isEmpty()) c += QStringLiteral(""); r += i18n("%1", c); QString sc = QStringLiteral("").arg(_sub); QString scname = _db->subclass(_class, _sub); if (!scname.isEmpty()) sc += QStringLiteral(""); r += i18n("%1", sc); QString pr = QStringLiteral("").arg(_prot); QString prname = _db->protocol(_class, _sub, _prot); if (!prname.isEmpty()) pr += QStringLiteral(""); r += i18n("%1", pr); #if !(defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)) r += ki18n("") .subs(_verMajor,0,16).subs(_verMinor,2,16,QChar::fromLatin1('0')) .toString(); #endif r += QLatin1String(""); QString v = QString::number(_vendorID, 16); QString name = _db->vendor(_vendorID); if (!name.isEmpty()) v += QStringLiteral(""); r += i18n("", v); QString p = QString::number(_prodID, 16); QString pname = _db->device(_vendorID, _prodID); if (!pname.isEmpty()) p += QStringLiteral(""); r += i18n("", p); r += ki18n("") .subs(_revMajor,0,16).subs(_revMinor,2,16,QChar::fromLatin1('0')) .toString(); r += QLatin1String(""); r += i18n("", _speed); r += i18n("", _channels); #if (defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)) && !defined(DISABLE_USBDEVICES_FREEBSD) if ( _power ) r += i18n("", _power); else r += i18n(""); r += i18n("", _devnodes.at(0)); if ( _devnodes.count() > 1 ) { QStringList::const_iterator it = _devnodes.constBegin(); ++it; for (; it != _devnodes.constEnd(); ++it ) r += QStringLiteral(""); } #else r += i18n("", _maxPacketSize); #endif r += QLatin1String(""); if (_hasBW) { r += i18n("", _bwUsed, _bwTotal, _bwPercent); r += i18n("", _bwIntr); r += i18n("", _bwIso); r += QLatin1String(""); } r += QLatin1String("
%1(") + i18n(cname.toLatin1().constData()) +QStringLiteral(")
Class
%1(") + i18n(scname.toLatin1().constData()) +QStringLiteral(")
Subclass
%1(") + prname +QStringLiteral(")
Protocol
USB Version%1.%2
(") + name +QStringLiteral(")
Vendor ID0x%1
(") + pname +QStringLiteral(")
Product ID0x%1
Revision%1.%2
Speed%1 Mbit/s
Channels%1
Power Consumption%1 mA
Power Consumptionself powered
Attached Devicenodes%1
") + *it + QStringLiteral("
Max. Packet Size%1
Bandwidth%1 of %2 (%3%)
Intr. requests%1
Isochr. requests%1
"); return r; } #if !(defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)) bool USBDevice::parse(const QString &fname) { _devices.clear(); QString result; // read in the complete file // // Note: we can't use a QTextStream, as the files in /proc // are pseudo files with zero length char buffer[256]; int fd =:: open(QFile::encodeName(fname).constData(), O_RDONLY); if (fd<0) return false; if (fd >= 0) { ssize_t count; while ((count = ::read(fd, buffer, 256)) > 0) result.append(QString::fromLatin1(buffer).leftRef(count)); ::close(fd); } // read in the device infos USBDevice *device = nullptr; int start=0, end; result.remove(QRegExp(QStringLiteral("^\n"))); while ((end = result.indexOf(QLatin1Char('\n'), start)) > 0) { QString line = result.mid(start, end-start); if (line.startsWith(QLatin1String("T:"))) device = new USBDevice(); if (device) device->parseLine(line); start = end+1; } return true; } bool USBDevice::parseSys(const QString &dname) { QDir d(dname); d.setNameFilters(QStringList() << QStringLiteral("usb*")); const QStringList list = d.entryList(); for (QStringList::const_iterator it = list.constBegin(), total = list.constEnd(); it != total; ++it) { USBDevice* device = new USBDevice(); int bus = 0; QRegExp bus_reg(QStringLiteral("[a-z]*([0-9]+)")); if (bus_reg.indexIn(*it) != -1) bus = bus_reg.cap(1).toInt(); device->parseSysDir(bus, 0, 0, d.absolutePath() + QLatin1Char('/') + *it); } return d.count(); } #else // Unused by *BSD bool USBDevice::parseSys(const QString &fname) { Q_UNUSED(fname) return true; } # if defined(DISABLE_USBDEVICES_FREEBSD) /* * FIXME: The USB subsystem has changed a lot in FreeBSD 8.0 * Support for it must be written. */ bool USBDevice::parse(const QString &fname) { Q_UNUSED(fname) return true; } # else /* * FreeBSD support by Markus Brueffer * * Basic idea and some code fragments were taken from FreeBSD's usbdevs(8), * originally developed for NetBSD, so this code should work with no or * only little modification on NetBSD. */ void USBDevice::collectData( int fd, int level, usb_device_info &di, int parent) { // determine data for this device _level = level; _parent = parent; _bus = di.udi_bus; _device = di.udi_addr; _product = QLatin1String(di.udi_product); if ( _device == 1 ) _product += ' ' + QString::number( _bus ); _manufacturer = QLatin1String(di.udi_vendor); _prodID = di.udi_productNo; _vendorID = di.udi_vendorNo; _class = di.udi_class; _sub = di.udi_subclass; _prot = di.udi_protocol; _power = di.udi_power; _channels = di.udi_nports; // determine the speed #if defined(__DragonFly__) || (defined(Q_OS_FREEBSD) && __FreeBSD_version > 490102) || defined(Q_OS_NETBSD) switch (di.udi_speed) { case USB_SPEED_LOW: _speed = 1.5; break; case USB_SPEED_FULL: _speed = 12.0; break; case USB_SPEED_HIGH: _speed = 480.0; break; } #else _speed = di.udi_lowspeed ? 1.5 : 12.0; #endif // Get all attached devicenodes for ( int i = 0; i < USB_MAX_DEVNAMES; ++i ) if ( di.udi_devnames[i][0] ) _devnodes << di.udi_devnames[i]; // For compatibility, split the revision number sscanf( di.udi_release, "%x.%x", &_revMajor, &_revMinor ); // Cycle through the attached devices if there are any for ( int p = 0; p < di.udi_nports; ++p ) { // Get data for device struct usb_device_info di2; di2.udi_addr = di.udi_ports[p]; if ( di2.udi_addr >= USB_MAX_DEVICES ) continue; if ( ioctl(fd, USB_DEVICEINFO, &di2) == -1 ) continue; // Only add the device if we didn't detect it, yet if (!find( di2.udi_bus, di2.udi_addr ) ) { USBDevice *device = new USBDevice(); device->collectData( fd, level + 1, di2, di.udi_addr ); } } } bool USBDevice::parse(const QString &fname) { Q_UNUSED(fname) static bool showErrorMessage = true; bool error = false; _devices.clear(); QFile controller("/dev/usb0"); int i = 1; while ( controller.exists() ) { // If the devicenode exists, continue with further inspection if ( controller.open(QIODevice::ReadOnly) ) { for ( int addr = 1; addr < USB_MAX_DEVICES; ++addr ) { struct usb_device_info di; di.udi_addr = addr; if ( ioctl(controller.handle(), USB_DEVICEINFO, &di) != -1 ) { if (!find( di.udi_bus, di.udi_addr ) ) { USBDevice *device = new USBDevice(); device->collectData( controller.handle(), 0, di, 0); } } } controller.close(); #ifndef Q_OS_NETBSD } else { error = true; #endif } controller.setFileName( QString::fromLocal8Bit("/dev/usb%1").arg(i++) ); } if ( showErrorMessage && error ) { showErrorMessage = false; 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.")); } return true; } # endif // defined(DISABLE_USBDEVICES_FREEBSD) #endif // !(defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD))