summaryrefslogtreecommitdiffstats
path: root/kcontrol/usbview/usbdevices.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kcontrol/usbview/usbdevices.cpp')
-rw-r--r--kcontrol/usbview/usbdevices.cpp431
1 files changed, 431 insertions, 0 deletions
diff --git a/kcontrol/usbview/usbdevices.cpp b/kcontrol/usbview/usbdevices.cpp
new file mode 100644
index 000000000..3d557a7ed
--- /dev/null
+++ b/kcontrol/usbview/usbdevices.cpp
@@ -0,0 +1,431 @@
+/***************************************************************************
+ * Copyright (C) 2001 by Matthias Hoelzer-Kluepfel <[email protected]> *
+ * *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qregexp.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "usbdb.h"
+#include "usbdevices.h"
+
+#include <math.h>
+
+#ifdef Q_OS_FREEBSD
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#endif
+
+QPtrList<USBDevice> 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);
+ _devices.setAutoDelete(true);
+
+ if (!_db)
+ _db = new USBDB;
+}
+
+static QString catFile(QString fname)
+{
+ char buffer[256];
+ QString result;
+ int fd = ::open(QFile::encodeName(fname), O_RDONLY);
+ if (fd<0)
+ return QString::null;
+
+ if (fd >= 0)
+ {
+ ssize_t count;
+ while ((count = ::read(fd, buffer, 256)) > 0)
+ result.append(QString(buffer).left(count));
+
+ ::close(fd);
+ }
+ return result.stripWhiteSpace();
+}
+
+void USBDevice::parseSysDir(int bus, int parent, int level, QString dname)
+{
+ _level = level;
+ _parent = parent;
+ _manufacturer = catFile(dname + "/manufacturer");
+ _product = catFile(dname + "/product");
+
+ _bus = bus;
+ _device = catFile(dname + "/devnum").toUInt();
+
+ if (_device == 1)
+ _product += QString(" (%1)").arg(_bus);
+
+ _vendorID = catFile(dname + "/idVendor").toUInt(0, 16);
+ _prodID = catFile(dname + "/idProduct").toUInt(0, 16);
+
+ _class = catFile(dname + "/bDeviceClass").toUInt(0, 16);
+ _sub = catFile(dname + "/bDeviceSubClass").toUInt(0, 16);
+ _maxPacketSize = catFile(dname + "/bMaxPacketSize0").toUInt();
+
+ _speed = catFile(dname + "/speed").toDouble();
+ _serial = catFile(dname + "/serial");
+ _channels = catFile(dname + "/maxchild").toUInt();
+
+ double version = catFile(dname + "/version").toDouble();
+ _verMajor = int(version);
+ _verMinor = int(10*(version - floor(version)));
+
+ QDir dir(dname);
+ dir.setNameFilter(QString("%1-*").arg(bus));
+ dir.setFilter(QDir::Dirs);
+ QStringList list = dir.entryList();
+
+ for(QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
+ if ((*it).contains(':'))
+ continue;
+
+ USBDevice* dev = new USBDevice();
+ dev->parseSysDir(bus, ++level, _device, dname + "/" + *it);
+ }
+}
+
+void USBDevice::parseLine(QString line)
+{
+ if (line.startsWith("T:"))
+ sscanf(line.local8Bit().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("S: Manufacturer"))
+ _manufacturer = line.mid(17);
+ else if (line.startsWith("S: Product")) {
+ _product = line.mid(12);
+ /* add bus number to root devices */
+ if (_device==1)
+ _product += QString(" (%1)").arg(_bus);
+ }
+ else if (line.startsWith("S: SerialNumber"))
+ _serial = line.mid(17);
+ else if (line.startsWith("B:"))
+ {
+ sscanf(line.local8Bit().data(),
+ "B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d",
+ &_bwUsed, &_bwTotal, &_bwPercent, &_bwIntr, &_bwIso);
+ _hasBW = true;
+ }
+ else if (line.startsWith("D:"))
+ {
+ char buffer[11];
+ sscanf(line.local8Bit().data(),
+ "D: Ver=%x.%x Cls=%x(%10s) Sub=%x Prot=%x MxPS=%d #Cfgs=%d",
+ &_verMajor, &_verMinor, &_class, buffer, &_sub, &_prot, &_maxPacketSize, &_configs);
+ _className = buffer;
+ }
+ else if (line.startsWith("P:"))
+ sscanf(line.local8Bit().data(),
+ "P: Vendor=%x ProdID=%x Rev=%x.%x",
+ &_vendorID, &_prodID, &_revMajor, &_revMinor);
+}
+
+
+USBDevice *USBDevice::find(int bus, int device)
+{
+ QPtrListIterator<USBDevice> it(_devices);
+ for ( ; it.current(); ++it)
+ if (it.current()->bus() == bus && it.current()->device() == device)
+ return it.current();
+ return 0;
+}
+
+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 = "<qml><h2><center>" + product() + "</center></h2><br/><hl/>";
+
+ if (!_manufacturer.isEmpty())
+ r += i18n("<b>Manufacturer:</b> ") + _manufacturer + "<br/>";
+ if (!_serial.isEmpty())
+ r += i18n("<b>Serial #:</b> ") + _serial + "<br/>";
+
+ r += "<br/><table>";
+
+ QString c = QString("<td>%1</td>").arg(_class);
+ QString cname = _db->cls(_class);
+ if (!cname.isEmpty())
+ c += "<td>(" + i18n(cname.latin1()) +")</td>";
+ r += i18n("<tr><td><i>Class</i></td>%1</tr>").arg(c);
+ QString sc = QString("<td>%1</td>").arg(_sub);
+ QString scname = _db->subclass(_class, _sub);
+ if (!scname.isEmpty())
+ sc += "<td>(" + i18n(scname.latin1()) +")</td>";
+ r += i18n("<tr><td><i>Subclass</i></td>%1</tr>").arg(sc);
+ QString pr = QString("<td>%1</td>").arg(_prot);
+ QString prname = _db->protocol(_class, _sub, _prot);
+ if (!prname.isEmpty())
+ pr += "<td>(" + prname +")</td>";
+ r += i18n("<tr><td><i>Protocol</i></td>%1</tr>").arg(pr);
+#ifndef Q_OS_FREEBSD
+ r += i18n("<tr><td><i>USB Version</i></td><td>%1.%2</td></tr>")
+ .arg(_verMajor,0,16)
+ .arg(QString::number(_verMinor,16).prepend('0').right(2));
+#endif
+ r += "<tr><td></td></tr>";
+
+ QString v = QString::number(_vendorID,16);
+ QString name = _db->vendor(_vendorID);
+ if (!name.isEmpty())
+ v += "<td>(" + name +")</td>";
+ r += i18n("<tr><td><i>Vendor ID</i></td><td>0x%1</td></tr>").arg(v);
+ QString p = QString::number(_prodID,16);
+ QString pname = _db->device(_vendorID, _prodID);
+ if (!pname.isEmpty())
+ p += "<td>(" + pname +")</td>";
+ r += i18n("<tr><td><i>Product ID</i></td><td>0x%1</td></tr>").arg(p);
+ r += i18n("<tr><td><i>Revision</i></td><td>%1.%2</td></tr>")
+ .arg(_revMajor,0,16)
+ .arg(QString::number(_revMinor,16).prepend('0').right(2));
+ r += "<tr><td></td></tr>";
+
+ r += i18n("<tr><td><i>Speed</i></td><td>%1 Mbit/s</td></tr>").arg(_speed);
+ r += i18n("<tr><td><i>Channels</i></td><td>%1</td></tr>").arg(_channels);
+#ifdef Q_OS_FREEBSD
+ if ( _power )
+ r += i18n("<tr><td><i>Power Consumption</i></td><td>%1 mA</td></tr>").arg(_power);
+ else
+ r += i18n("<tr><td><i>Power Consumption</i></td><td>self powered</td></tr>");
+ r += i18n("<tr><td><i>Attached Devicenodes</i></td><td>%1</td></tr>").arg(*_devnodes.at(0));
+ if ( _devnodes.count() > 1 )
+ for ( QStringList::Iterator it = _devnodes.at(1); it != _devnodes.end(); ++it )
+ r += "<tr><td></td><td>" + *it + "</td></tr>";
+#else
+ r += i18n("<tr><td><i>Max. Packet Size</i></td><td>%1</td></tr>").arg(_maxPacketSize);
+#endif
+ r += "<tr><td></td></tr>";
+
+ if (_hasBW)
+ {
+ r += i18n("<tr><td><i>Bandwidth</i></td><td>%1 of %2 (%3%)</td></tr>").arg(_bwUsed).arg(_bwTotal).arg(_bwPercent);
+ r += i18n("<tr><td><i>Intr. requests</i></td><td>%1</td></tr>").arg(_bwIntr);
+ r += i18n("<tr><td><i>Isochr. requests</i></td><td>%1</td></tr>").arg(_bwIso);
+ r += "<tr><td></td></tr>";
+ }
+
+ r += "</table>";
+
+ return r;
+}
+
+
+#ifndef Q_OS_FREEBSD
+bool USBDevice::parse(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), O_RDONLY);
+ if (fd<0)
+ return false;
+
+ if (fd >= 0)
+ {
+ ssize_t count;
+ while ((count = ::read(fd, buffer, 256)) > 0)
+ result.append(QString(buffer).left(count));
+
+ ::close(fd);
+ }
+
+ // read in the device infos
+ USBDevice *device = 0;
+ int start=0, end;
+ result.replace(QRegExp("^\n"),"");
+ while ((end = result.find('\n', start)) > 0)
+ {
+ QString line = result.mid(start, end-start);
+
+ if (line.startsWith("T:"))
+ device = new USBDevice();
+
+ if (device)
+ device->parseLine(line);
+
+ start = end+1;
+ }
+ return true;
+}
+
+bool USBDevice::parseSys(QString dname)
+{
+ QDir d(dname);
+ d.setNameFilter("usb*");
+ QStringList list = d.entryList();
+
+ for(QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
+ USBDevice* device = new USBDevice();
+
+ int bus = 0;
+ QRegExp bus_reg("[a-z]*([0-9]+)");
+ if (bus_reg.search(*it) != -1)
+ bus = bus_reg.cap(1).toInt();
+
+
+ device->parseSysDir(bus, 0, 0, d.absPath() + "/" + *it);
+ }
+
+ return d.count();
+}
+
+#else
+
+/*
+ * FreeBSD support by Markus Brueffer <[email protected]>
+ *
+ * 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 = QString::fromLatin1(di.udi_product);
+ if ( _device == 1 )
+ _product += " " + QString::number( _bus );
+ _manufacturer = QString::fromLatin1(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 __FreeBSD_version > 490102
+ 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(QString 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(IO_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();
+ } else {
+ error = true;
+ }
+ controller.setName( 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