 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 <QLayout>
 #include <QSplitter>
 #include <QtGui/QTextEdit>
-#include <QTimer>
 #include <QHBoxLayout>
 #include <QList>
 #include <QTreeWidget>
@@ -20,6 +19,7 @@
 
 #include <kaboutdata.h>
 #include <kdialog.h>
+#include <solid/devicenotifier.h>
 
 #include <KPluginFactory>
 #include <KPluginLoader>
@@ -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<int, QTreeWidgetI
 void USBViewer::refresh() {
 	QMap<int, QTreeWidgetItem*> 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 <math.h>
 
-#if defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
-#include <sys/ioctl.h>
-#include <sys/param.h>
+#include <config-kcmusb.h>
+#if defined(HAVE_LIBUSB1)
+#include <libusb.h>
 #endif
 
 QList<USBDevice*> 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 += "<br/><table>";
 
+	r += i18n("<tr><td><i>Bus number</i></td><td>%1</td></tr>", _bus);
+	r += i18n("<tr><td><i>Device address</i></td><td>%1</td></tr>", _device);
+	r += "<tr><td></td></tr>";
+
 	QString c = QString("<td>%1</td>").arg(_class);
 	QString cname = _db->cls(_class);
 	if (!cname.isEmpty())
@@ -175,11 +181,9 @@ QString USBDevice::dump() {
 	if (!prname.isEmpty())
 		pr += "<td>(" + prname +")</td>";
 	r += i18n("<tr><td><i>Protocol</i></td>%1</tr>", pr);
-#if !(defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD))
 	r += ki18n("<tr><td><i>USB Version</i></td><td>%1.%2</td></tr>")
 	.subs(_verMajor,0,16).subs(_verMinor,2,16,QChar::fromLatin1('0'))
 	.toString();
-#endif
 	r += "<tr><td></td></tr>";
 
 	QString v = QString::number(_vendorID, 16);
@@ -198,22 +202,15 @@ QString USBDevice::dump() {
 	r += "<tr><td></td></tr>";
 
 	r += i18n("<tr><td><i>Speed</i></td><td>%1 Mbit/s</td></tr>", _speed);
-	r += i18n("<tr><td><i>Channels</i></td><td>%1</td></tr>", _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("<tr><td><i>Power Consumption</i></td><td>%1 mA</td></tr>", _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>", _devnodes.at(0));
-	if ( _devnodes.count() > 1 ) {
-		QStringList::const_iterator it = _devnodes.constBegin();
-		++it;
-		for (; it != _devnodes.constEnd(); ++it )
-		r += "<tr><td></td><td>" + *it + "</td></tr>";
-	}
-#else
+	r += i18n("<tr><td><i>Power Consumption</i></td><td>unknown</td></tr>");
+#else // defined(HAVE_LIBUSB1)
+	r += i18n("<tr><td><i>Channels</i></td><td>%1</td></tr>", _channels);
+#endif // defined(HAVE_LIBUSB1)
 	r += i18n("<tr><td><i>Max. Packet Size</i></td><td>%1</td></tr>", _maxPacketSize);
-#endif
 	r += "<tr><td></td></tr>";
 
 	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 <markus@brueffer.de>
- *
- * 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 <QList>
 #include <QString>
 
-#if defined(__DragonFly__)
-#include <bus/usb/usb.h>
-#include <QStringList>
-#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
-#include <sys/param.h>
-# if defined(__FreeBSD_version) && __FreeBSD_version >= 800100
-#  define DISABLE_USBDEVICES_FREEBSD
-#  warning "The USB subsystem has changed in 8.0. Disabling."
-# else
-#  include <dev/usb/usb.h>
-#  include <QStringList>
-# endif
+#include <config-kcmusb.h>
+#if defined(HAVE_LIBUSB1)
+#include <libusb.h>
 #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
