Use libusb-1 to query info about usb devices on all platforms, leave old method as a fallback for Linux only. Remove *BSD specific code, it doesn't work on FreeBSD 8.x and greater. Old code probably works on NetBSD, but let it use libusb-1 as well. Use DeviceNotifier instead of polling. --- /dev/null +++ cmake/modules/FindLibUSB1.cmake @@ -0,0 +1,21 @@ +# - Try to find libusb v1.0 library +# Once done this defines +# +# LIBUSB1_FOUND - system has libusb +# LIBUSB1_INCLUDE_DIR - libusb include directory +# LIBUSB1_LIBRARY - libusb library + +find_package(PkgConfig) +pkg_check_modules(PC_LIBUSB1 QUIET libusb-1.0) + +find_path(LIBUSB1_INCLUDE_DIR libusb.h + HINTS ${PC_LIBUSB1_INCLUDEDIR} ${PC_LIBUSB1_INCLUDE_DIRS}) + +# On FreeBSD libusb provides both v0.1 and v1.0 API +find_library(LIBUSB1_LIBRARY NAMES usb-1.0 usb + HINTS ${PC_LIBUSB1_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LIBUSB1 DEFAULT_MSG LIBUSB1_LIBRARY LIBUSB1_INCLUDE_DIR) + +mark_as_advanced(LIBUSB1_INCLUDE_DIR LIBUSB1_LIBRARY) --- kinfocenter/Modules/usbview/CMakeLists.txt +++ kinfocenter/Modules/usbview/CMakeLists.txt @@ -1,15 +1,25 @@ +macro_optional_find_package(LibUSB1) +macro_bool_to_01(LIBUSB1_FOUND HAVE_LIBUSB1) +macro_log_feature(LIBUSB1_FOUND "libusb-1" "User level access to USB devices" "http://libusb.sourceforge.net/" FALSE "" "Provides usb info support in KControl.") - +configure_file (config-kcmusb.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kcmusb.h ) ########### next target ############### +if (LIBUSB1_FOUND) + include_directories( ${LIBUSB1_INCLUDE_DIR} ) +endif (LIBUSB1_FOUND) + set(kcm_usb_PART_SRCS kcmusb.cpp usbdevices.cpp usbdb.cpp ) kde4_add_plugin(kcm_usb ${kcm_usb_PART_SRCS}) -target_link_libraries(kcm_usb ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY}) +target_link_libraries(kcm_usb ${KDE4_KDEUI_LIBS} ${KDE4_SOLID_LIBS} ${QT_QTGUI_LIBRARY}) +if (LIBUSB1_FOUND) + target_link_libraries(kcm_usb ${LIBUSB1_LIBRARY}) +endif (LIBUSB1_FOUND) install(TARGETS kcm_usb DESTINATION ${PLUGIN_INSTALL_DIR} ) --- /dev/null +++ kinfocenter/Modules/usbview/config-kcmusb.h.cmake @@ -0,0 +1,2 @@ +/* Defined if you have libusb */ +#cmakedefine HAVE_LIBUSB1 1 --- kinfocenter/Modules/usbview/kcmusb.cpp +++ kinfocenter/Modules/usbview/kcmusb.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -20,6 +19,7 @@ #include #include +#include #include #include @@ -63,11 +63,8 @@ USBViewer::USBViewer(QWidget *parent, const QVariantList &) : _details = new QTextEdit(splitter); _details->setReadOnly(true); - QTimer *refreshTimer = new QTimer(this); - // 1 sec seems to be a good compromise between latency and polling load. - refreshTimer->start(1000); - - connect(refreshTimer, SIGNAL(timeout()), SLOT(refresh())); + connect(Solid::DeviceNotifier::instance(),SIGNAL(deviceAdded(QString)), SLOT(refresh())); + connect(Solid::DeviceNotifier::instance(),SIGNAL(deviceRemoved(const QString)), SLOT(refresh())); connect(_devices, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(selectionChanged(QTreeWidgetItem*))); KAboutData *about = new KAboutData(I18N_NOOP("kcmusb"), 0, ki18n("KDE USB Viewer"), @@ -113,8 +110,12 @@ static void delete_recursive(QTreeWidgetItem *item, const QMap new_items; +#if defined(HAVE_LIBUSB1) + USBDevice::parse(); +#else if (!USBDevice::parse("/proc/bus/usb/devices")) USBDevice::parseSys("/sys/bus/usb/devices"); +#endif int level = 0; bool found = true; --- kinfocenter/Modules/usbview/usbdevices.cpp +++ kinfocenter/Modules/usbview/usbdevices.cpp @@ -27,9 +27,9 @@ #include -#if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) -#include -#include +#include +#if defined(HAVE_LIBUSB1) +#include #endif QList USBDevice::_devices; @@ -48,6 +48,7 @@ USBDevice::~USBDevice() { } +#if !defined(HAVE_LIBUSB1) static QString catFile(QString fname) { char buffer[256]; QString result; @@ -129,6 +130,7 @@ void USBDevice::parseLine(const QString& line) { } else if (line.startsWith("P:")) sscanf(line.toLocal8Bit().data(), "P: Vendor=%x ProdID=%x Rev=%x.%x", &_vendorID, &_prodID, &_revMajor, &_revMinor); } +#endif // !defined(HAVE_LIBUSB1) USBDevice* USBDevice::find(int bus, int device) { foreach(USBDevice* usbDevice, _devices) { @@ -160,6 +162,10 @@ QString USBDevice::dump() { r += "
"; + r += i18n("", _bus); + r += i18n("", _device); + r += ""; + QString c = QString("").arg(_class); QString cname = _db->cls(_class); if (!cname.isEmpty()) @@ -175,11 +181,9 @@ QString USBDevice::dump() { if (!prname.isEmpty()) pr += ""; 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 += ""; QString v = QString::number(_vendorID, 16); @@ -198,22 +202,15 @@ QString USBDevice::dump() { r += ""; r += i18n("", _speed); - r += i18n("", _channels); -#if (defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)) && !defined(DISABLE_USBDEVICES_FREEBSD) - if ( _power ) +#if defined(HAVE_LIBUSB1) + if ( _power != -1 ) 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 += ""; - } -#else + r += i18n(""); +#else // defined(HAVE_LIBUSB1) + r += i18n("", _channels); +#endif // defined(HAVE_LIBUSB1) r += i18n("", _maxPacketSize); -#endif r += ""; if (_hasBW) { @@ -228,7 +225,82 @@ QString USBDevice::dump() { return r; } -#if !(defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)) +#if defined(HAVE_LIBUSB1) + +void USBDevice::dump_usbdev_info(libusb_device *dev) { + + _bus = libusb_get_bus_number(dev); + _device = libusb_get_device_address(dev); + + switch (libusb_get_device_speed(dev)) { + case LIBUSB_SPEED_LOW: _speed = 1.5; break; + case LIBUSB_SPEED_FULL: _speed = 12; break; + case LIBUSB_SPEED_HIGH: _speed = 480; break; + case LIBUSB_SPEED_SUPER: _speed = 5000; break; + } + + struct libusb_config_descriptor *conf; + if (libusb_get_active_config_descriptor(dev, &conf) == 0) { + _power = conf->MaxPower; + libusb_free_config_descriptor(conf); + } else { + _power = -1; + } + + struct libusb_device_descriptor desc; + if (libusb_get_device_descriptor(dev, &desc) == 0) { + _verMajor = desc.bcdUSB >> 8; + _verMinor = desc.bcdUSB & 0x00FF; + _class = desc.bDeviceClass; + _sub = desc.bDeviceSubClass; + _prot = desc.bDeviceProtocol; + _maxPacketSize = desc.bMaxPacketSize0; + _configs = desc.bNumConfigurations; + _vendorID = desc.idVendor; + _prodID = desc.idProduct; + _revMajor = desc.bcdDevice >> 8; + _revMinor = desc.bcdDevice & 0x00FF; + } + + libusb_device_handle *hdev; + uchar buf[256]; + if (libusb_open(dev, &hdev) == 0) { + if (libusb_get_string_descriptor_ascii(hdev, desc.iManufacturer, buf, sizeof(buf)) > 0) + _manufacturer = (char*) buf; + if (libusb_get_string_descriptor_ascii(hdev, desc.iProduct, buf, sizeof(buf)) > 0) + _product = (char*) buf; + if (libusb_get_string_descriptor_ascii(hdev, desc.iSerialNumber, buf, sizeof(buf)) > 0) + _serial = (char*) buf; + libusb_close(hdev); + } +} + +bool USBDevice::parse() { + _devices.clear(); + + int r = libusb_init(NULL); + if (r != 0) + return false; + + libusb_device **devs; + ssize_t cnt = libusb_get_device_list(NULL, &devs); + if (cnt < 0) + return false; + + libusb_device *dev; + int i = 0; + while ((dev = devs[i++]) != NULL) { + USBDevice* device = new USBDevice(); + device->dump_usbdev_info(dev); + } + libusb_free_device_list(devs, 1); + + libusb_exit(NULL); + return true; +} + +#else // defined(HAVE_LIBUSB1) +#if defined(Q_OS_LINUX) bool USBDevice::parse(const QString &fname) { _devices.clear(); @@ -290,146 +362,19 @@ bool USBDevice::parseSys(const QString &dname) { 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. - */ +#else // defined(Q_OS_LINUX) -bool USBDevice::parse(const QString &fname) -{ +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.")); - } +bool USBDevice::parseSys(const QString &dname) { + Q_UNUSED(dname) return true; } -# endif // defined(DISABLE_USBDEVICES_FREEBSD) -#endif // !(defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)) +#endif // defined(Q_OS_LINUX) +#endif // defined(HAVE_LIBUSB1) --- kinfocenter/Modules/usbview/usbdevices.h +++ kinfocenter/Modules/usbview/usbdevices.h @@ -14,18 +14,9 @@ #include #include -#if defined(__DragonFly__) -#include -#include -#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) -#include -# if defined(__FreeBSD_version) && __FreeBSD_version >= 800100 -# define DISABLE_USBDEVICES_FREEBSD -# warning "The USB subsystem has changed in 8.0. Disabling." -# else -# include -# include -# endif +#include +#if defined(HAVE_LIBUSB1) +#include #endif class USBDB; @@ -36,10 +27,12 @@ public: USBDevice(); ~USBDevice(); - +#if defined(HAVE_LIBUSB1) + void dump_usbdev_info(libusb_device *dev); +#else void parseLine(const QString &line); void parseSysDir(int bus, int parent, int level, const QString &line); - +#endif int level() const { return _level; } @@ -60,8 +53,12 @@ public: return _devices; } static USBDevice *find(int bus, int device); +#if defined(HAVE_LIBUSB1) + static bool parse(); +#else static bool parse(const QString& fname); static bool parseSys(const QString& fname); +#endif private: @@ -82,10 +79,6 @@ private: unsigned int _vendorID, _prodID, _revMajor, _revMinor; -#if (defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)) && !defined(DISABLE_USBDEVICES_FREEBSD) - void collectData( int fd, int level, usb_device_info &di, int parent ); - QStringList _devnodes; -#endif }; #endif
Bus number%1
Device address%1
%1(" + prname +")
Protocol
USB Version%1.%2
Speed%1 Mbit/s
Channels%1
Power Consumption%1 mA
Power Consumptionself powered
Attached Devicenodes%1
" + *it + "
Power Consumptionunknown
Channels%1
Max. Packet Size%1