[Pcsclite-cvs-commit] r5638 - in /trunk/PCSC: configure.in src/Makefile.am src/PCSC/ifdhandler.h src/hotplug_generic.c src/hotplug_libhal.c src/hotplug_libudev.c src/hotplug_linux.c

rousseau at users.alioth.debian.org rousseau at users.alioth.debian.org
Fri Feb 25 13:37:00 UTC 2011


Author: rousseau
Date: Fri Feb 25 13:36:57 2011
New Revision: 5638

URL: http://svn.debian.org/wsvn/pcsclite/?sc=1&rev=5638
Log:
Use libudev instead of (deprecated) libhal for the USB hotplug mechanism.

Added:
    trunk/PCSC/src/hotplug_libudev.c   (with props)
Removed:
    trunk/PCSC/src/hotplug_libhal.c
Modified:
    trunk/PCSC/configure.in
    trunk/PCSC/src/Makefile.am
    trunk/PCSC/src/PCSC/ifdhandler.h
    trunk/PCSC/src/hotplug_generic.c
    trunk/PCSC/src/hotplug_linux.c

Modified: trunk/PCSC/configure.in
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/configure.in?rev=5638&op=diff
==============================================================================
--- trunk/PCSC/configure.in (original)
+++ trunk/PCSC/configure.in Fri Feb 25 13:36:57 2011
@@ -165,56 +165,56 @@
 	PCSCLITE_FEATURES="${PCSCLITE_FEATURES} usb"
 fi
 
-# --enable-libhal
-AC_ARG_ENABLE(libhal,
-	AC_HELP_STRING([--disable-libhal],[do not use libhal]),
-	[ use_libhal="${enableval}" ], [ use_libhal="${use_libhal-yes}" ] )
-
-# check if libhal is used
-if test "x$use_libhal" != xno ; then
-	PKG_CHECK_MODULES(LIBHAL, hal, [],
-		[ AC_MSG_ERROR([install libhal-dev or use --disable-libhal]) ])
+# --enable-libudev
+AC_ARG_ENABLE(libudev,
+	AC_HELP_STRING([--disable-libudev],[do not use libudev]),
+	[ use_libudev="${enableval}" ], [ use_libudev="${use_libudev-yes}" ] )
+
+# check if libudev is used
+if test "x$use_libudev" != xno ; then
+	PKG_CHECK_MODULES(LIBUDEV, libudev, [],
+		[ AC_MSG_ERROR([install libudev-dev or use --disable-libudev]) ])
 
 	saved_CPPFLAGS="$CPPFLAGS"
 	saved_LIBS="$LIBS"
 
-	CPPFLAGS="$CPPFLAGS $LIBHAL_CFLAGS"
-	LIBS="$LDFLAGS $LIBHAL_LIBS"
-
-	AC_CHECK_HEADERS(libhal.h, [],
-		[ AC_MSG_ERROR([libhal.h not found, use ./configure LIBHAL_CFLAGS=...]) ])
+	CPPFLAGS="$CPPFLAGS $LIBUDEV_CFLAGS"
+	LIBS="$LDFLAGS $LIBUDEV_LIBS"
+
+	AC_CHECK_HEADERS(libudev.h, [],
+		[ AC_MSG_ERROR([libudev.h not found, use ./configure LIBUDEV_CFLAGS=...]) ])
 
 	LIBS="$LIBS $COREFOUNDATION $IOKIT"
 
-	AC_MSG_CHECKING([for libhal_ctx_new])
-	AC_TRY_LINK_FUNC(libhal_ctx_new, [ AC_MSG_RESULT([yes]) ],
-		[ AC_MSG_ERROR([libhal not found, use ./configure LIBHAL_LIBS=...]) ])
-
-	# everything needed for libhal support is present
-	use_libhal=yes
+	AC_MSG_CHECKING([for udev_monitor_unref])
+	AC_TRY_LINK_FUNC(udev_monitor_unref, [ AC_MSG_RESULT([yes]) ],
+		[ AC_MSG_ERROR([udev_monitor_unref not found, use ./configure LIBUDEV_LIBS=...]) ])
+
+	# everything needed for libudev support is present
+	use_libudev=yes
 
 	CPPFLAGS="$saved_CPPFLAGS"
 	LIBS="$saved_LIBS"
 fi
-AC_SUBST(LIBHAL_CFLAGS)
-AC_SUBST(LIBHAL_LIBS)
-
-if test x$use_libhal = xyes; then
-  AC_DEFINE(HAVE_LIBHAL, 1, [Libhal is available])
-  PCSCLITE_FEATURES="${PCSCLITE_FEATURES} libhal"
+AC_SUBST(LIBUDEV_CFLAGS)
+AC_SUBST(LIBUDEV_LIBS)
+
+if test x$use_libudev = xyes; then
+  AC_DEFINE(HAVE_LIBUDEV, 1, [Libudev is available])
+  PCSCLITE_FEATURES="${PCSCLITE_FEATURES} libudev"
 fi
 
 # --enable-libusb
 AC_ARG_ENABLE(libusb,
 	AC_HELP_STRING([--enable-libusb],[use libusb]),
 	[ use_libusb="${enableval}" ],
-	[ if test "x$use_libhal" = xyes ; then use_libusb="${use_libusb-no}" ;
+	[ if test "x$use_libudev" = xyes ; then use_libusb="${use_libusb-no}" ;
 	else use_libusb="${use_libusb-yes}" ; fi ] )
 
 # check if libusb is used
 if test "x$use_libusb" != xno ; then
-	if  test "x$use_libhal" != xno ; then
-		AC_MSG_ERROR([You can't use libhal _and_ libusb. Select only one.])
+	if  test "x$use_libudev" != xno ; then
+		AC_MSG_ERROR([You can't use libudev _and_ libusb. Select only one.])
 	fi
 
 	PKG_CHECK_MODULES(LIBUSB, libusb-1.0, [],
@@ -370,7 +370,7 @@
 PCSC_ARCH:           ${PCSC_ARCH}
 
 pcscd binary          ${PCSCD_BINARY}
-libhal support:       ${use_libhal}
+libudev support:      ${use_libudev}
 libusb support:       ${use_libusb}
 USB drop directory:   ${usbdropdir}
 ATR parsing messages: ${debugatr}

Modified: trunk/PCSC/src/Makefile.am
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/Makefile.am?rev=5638&op=diff
==============================================================================
--- trunk/PCSC/src/Makefile.am (original)
+++ trunk/PCSC/src/Makefile.am Fri Feb 25 13:36:57 2011
@@ -14,7 +14,7 @@
 
 if ENABLE_USB
 USB_CONFIG = tokenparser.l \
-	hotplug_libhal.c \
+	hotplug_libudev.c \
 	hotplug_libusb.c \
 	hotplug_linux.c \
 	hotplug_macosx.c
@@ -83,12 +83,12 @@
 	winscard_msg_srv.c \
 	winscard_svc.c \
 	winscard_svc.h
-pcscd_CFLAGS = $(CFLAGS) $(PTHREAD_CFLAGS) $(LIBUSB_CFLAGS) $(LIBHAL_CFLAGS) \
+pcscd_CFLAGS = $(CFLAGS) $(PTHREAD_CFLAGS) $(LIBUSB_CFLAGS) $(LIBUDEV_CFLAGS) \
 	-DPCSCD -DSIMCLIST_NO_DUMPRESTORE
 pcscd_LDFLAGS = $(LDFLAGS) -export-dynamic
 pcscd_LDADD = \
 	$(PTHREAD_LIBS) $(COREFOUNDATION) \
-	$(LIBUSB_LIBS) $(LIBDL) $(IOKIT) $(LIBHAL_LIBS) \
+	$(LIBUSB_LIBS) $(LIBDL) $(IOKIT) $(LIBUDEV_LIBS) \
 	$(PTHREAD_LIBS) $(PTHREAD_CFLAGS)
 
 fix-rights: install-sbinPROGRAMS

Modified: trunk/PCSC/src/PCSC/ifdhandler.h
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/PCSC/ifdhandler.h?rev=5638&op=diff
==============================================================================
--- trunk/PCSC/src/PCSC/ifdhandler.h (original)
+++ trunk/PCSC/src/PCSC/ifdhandler.h Fri Feb 25 13:36:57 2011
@@ -426,25 +426,29 @@
   So it is something like: <tt>usb:08e6/3437:libusb:001:042</tt> under
   GNU/Linux.
 
-- libhal
-
-  If pcscd is compiled with libhal support instead of libusb (default
-  since pcsc-lite 1.4.100) the string will look like:
+- libudev
+
+  If pcscd is compiled with libudev support instead of libusb (default
+  since pcsc-lite 1.6.8) the string will look like:
 
   @code
-  printf("usb:%04x/%04x:libhal:%s", idVendor, idProduct, udi)
+  printf("usb:%04x/%04x:libudev:%d:%s", idVendor, idProduct,
+		bInterfaceNumber, devpath);
   @endcode
 
-  udi is the Universal Device Id at the HAL level.
+  bInterfaceNumber is the number of the interface on the device. It is
+  only usefull for devices with more than one CCID interface.
+
+  devpath is the filename of the device on the file system.
 
   So it is something like:
-  <tt>usb:08e6/3437:libhal:/org/freedesktop/Hal/devices/usb_device_8e6_3437_noserial_if0</tt>
+  <tt>usb:08e6/3437:libudev:0:/dev/bus/usb/008/047</tt>
   under GNU/Linux.
 
 - other
 
   If the driver does not understand the <tt>:libusb:</tt> or
-  <tt>:libhal:</tt> scheme or if a new scheme is used, the driver should
+  <tt>:libudev:</tt> scheme or if a new scheme is used, the driver should
   ignore the part it does not understand instead of failing.
 
   The driver shall recognize the <tt>usb:VID/PID</tt> part and, only if

Modified: trunk/PCSC/src/hotplug_generic.c
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/hotplug_generic.c?rev=5638&op=diff
==============================================================================
--- trunk/PCSC/src/hotplug_generic.c (original)
+++ trunk/PCSC/src/hotplug_generic.c Fri Feb 25 13:36:57 2011
@@ -27,7 +27,7 @@
 #define FALSE 0
 #endif
 
-#if !defined(__APPLE__) && !defined(HAVE_LIBUSB) && !defined(__linux__) && !defined(HAVE_LIBHAL)
+#if !defined(__APPLE__) && !defined(HAVE_LIBUSB) && !defined(__linux__) && !defined(HAVE_LIBUDEV)
 
 LONG HPSearchHotPluggables(void)
 {

Added: trunk/PCSC/src/hotplug_libudev.c
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/hotplug_libudev.c?rev=5638&op=file
==============================================================================
--- trunk/PCSC/src/hotplug_libudev.c (added)
+++ trunk/PCSC/src/hotplug_libudev.c Fri Feb 25 13:36:57 2011
@@ -1,0 +1,644 @@
+/*
+ * MUSCLE SmartCard Development ( http://www.linuxnet.com )
+ *
+ * Copyright (C) 2011
+ *  Ludovic Rousseau <ludovic.rousseau at free.fr>
+ *
+ * $Id$
+ */
+
+/**
+ * @file
+ * @brief This provides a search API for hot pluggble devices using libudev
+ */
+
+#include "config.h"
+#if defined(HAVE_LIBUDEV) && defined(USE_USB)
+
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <libudev.h>
+
+#include "debuglog.h"
+#include "parser.h"
+#include "readerfactory.h"
+#include "sys_generic.h"
+#include "hotplug.h"
+#include "utils.h"
+#include "strlcpycat.h"
+
+#undef DEBUG_HOTPLUG
+#define ADD_SERIAL_NUMBER
+#define ADD_INTERFACE_NAME
+
+#define FALSE			0
+#define TRUE			1
+
+pthread_mutex_t usbNotifierMutex;
+
+static pthread_t usbNotifyThread;
+static int driverSize = -1;
+static char AraKiriHotPlug = FALSE;
+
+/**
+ * keep track of drivers in a dynamically allocated array
+ */
+static struct _driverTracker
+{
+	unsigned int manuID;
+	unsigned int productID;
+
+	char *bundleName;
+	char *libraryPath;
+	char *readerName;
+	char *CFBundleName;
+} *driverTracker = NULL;
+#define DRIVER_TRACKER_SIZE_STEP 10
+
+/* The CCID driver already supports 176 readers.
+ * We start with a big array size to avoid reallocation. */
+#define DRIVER_TRACKER_INITIAL_SIZE 200
+
+typedef enum {
+ READER_ABSENT,
+ READER_PRESENT,
+ READER_FAILED
+} readerState_t;
+
+/**
+ * keep track of PCSCLITE_MAX_READERS_CONTEXTS simultaneous readers
+ */
+static struct _readerTracker
+{
+	readerState_t status;	/** reader state */
+	char bInterfaceNumber;	/** interface number on the device */
+	char *devpath;	/**< device name seen by udev */
+	char *fullName;	/**< full reader name (including serial number) */
+} readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
+
+
+static LONG HPReadBundleValues(void)
+{
+	LONG rv;
+	DIR *hpDir;
+	struct dirent *currFP = NULL;
+	char fullPath[FILENAME_MAX];
+	char fullLibPath[FILENAME_MAX];
+	int listCount = 0;
+
+	hpDir = opendir(PCSCLITE_HP_DROPDIR);
+
+	if (NULL == hpDir)
+	{
+		Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
+		Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
+		return -1;
+	}
+
+	/* allocate a first array */
+	driverSize = DRIVER_TRACKER_INITIAL_SIZE;
+	driverTracker = calloc(driverSize, sizeof(*driverTracker));
+	if (NULL == driverTracker)
+	{
+		Log1(PCSC_LOG_CRITICAL, "Not enough memory");
+		return -1;
+	}
+
+#define GET_KEY(key, values) \
+	rv = LTPBundleFindValueWithKey(&plist, key, values); \
+	if (rv) \
+	{ \
+		Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
+			fullPath); \
+		continue; \
+	}
+
+	while ((currFP = readdir(hpDir)) != 0)
+	{
+		if (strstr(currFP->d_name, ".bundle") != 0)
+		{
+			unsigned int alias;
+			list_t plist, *values;
+			list_t *manuIDs, *productIDs, *readerNames;
+			char *CFBundleName;
+			char *libraryPath;
+
+			/*
+			 * The bundle exists - let's form a full path name and get the
+			 * vendor and product ID's for this particular bundle
+			 */
+			(void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
+				PCSCLITE_HP_DROPDIR, currFP->d_name);
+			fullPath[sizeof(fullPath) - 1] = '\0';
+
+			rv = bundleParse(fullPath, &plist);
+			if (rv)
+				continue;
+
+			/* get CFBundleExecutable */
+			GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
+			libraryPath = list_get_at(values, 0);
+			(void)snprintf(fullLibPath, sizeof(fullLibPath),
+				"%s/%s/Contents/%s/%s",
+				PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
+				libraryPath);
+			fullLibPath[sizeof(fullLibPath) - 1] = '\0';
+
+			GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
+			GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
+			GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
+
+			/* Get CFBundleName */
+			rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
+				&values);
+			if (rv)
+				CFBundleName = NULL;
+			else
+				CFBundleName = strdup(list_get_at(values, 0));
+
+			/* while we find a nth ifdVendorID in Info.plist */
+			for (alias=0; alias<list_size(manuIDs); alias++)
+			{
+				char *value;
+
+				/* variables entries */
+				value = list_get_at(manuIDs, alias);
+				driverTracker[listCount].manuID = strtol(value, NULL, 16);
+
+				value = list_get_at(productIDs, alias);
+				driverTracker[listCount].productID = strtol(value, NULL, 16);
+
+				driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
+
+				/* constant entries for a same driver */
+				driverTracker[listCount].bundleName = strdup(currFP->d_name);
+				driverTracker[listCount].libraryPath = strdup(fullLibPath);
+				driverTracker[listCount].CFBundleName = CFBundleName;
+
+#ifdef DEBUG_HOTPLUG
+				Log2(PCSC_LOG_INFO, "Found driver for: %s",
+					driverTracker[listCount].readerName);
+#endif
+				listCount++;
+				if (listCount >= driverSize)
+				{
+					int i;
+
+					/* increase the array size */
+					driverSize += DRIVER_TRACKER_SIZE_STEP;
+#ifdef DEBUG_HOTPLUG
+					Log2(PCSC_LOG_INFO,
+						"Increase driverTracker to %d entries", driverSize);
+#endif
+					driverTracker = realloc(driverTracker,
+						driverSize * sizeof(*driverTracker));
+					if (NULL == driverTracker)
+					{
+						Log1(PCSC_LOG_CRITICAL, "Not enough memory");
+						driverSize = -1;
+						return -1;
+					}
+
+					/* clean the newly allocated entries */
+					for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
+					{
+						driverTracker[i].manuID = 0;
+						driverTracker[i].productID = 0;
+						driverTracker[i].bundleName = NULL;
+						driverTracker[i].libraryPath = NULL;
+						driverTracker[i].readerName = NULL;
+						driverTracker[i].CFBundleName = NULL;
+					}
+				}
+			}
+			bundleRelease(&plist);
+		}
+	}
+
+	driverSize = listCount;
+	(void)closedir(hpDir);
+
+#ifdef DEBUG_HOTPLUG
+	Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
+#endif
+
+	return 0;
+} /* HPReadBundleValues */
+
+
+/*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
+	const char *devpath)
+{
+	int i;
+	unsigned int idVendor, idProduct;
+	static struct _driverTracker *classdriver, *driver;
+	const char *str;
+
+	str = udev_device_get_sysattr_value(dev, "idVendor");
+	if (!str)
+	{
+		Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
+		return NULL;
+	}
+	sscanf(str, "%X", &idVendor);
+
+	str = udev_device_get_sysattr_value(dev, "idProduct");
+	if (!str)
+	{
+		Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
+		return NULL;
+	}
+	sscanf(str, "%X", &idProduct);
+
+	Log4(PCSC_LOG_DEBUG,
+		"Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
+		idVendor, idProduct, devpath);
+
+	classdriver = NULL;
+	driver = NULL;
+	/* check if the device is supported by one driver */
+	for (i=0; i<driverSize; i++)
+	{
+		if (driverTracker[i].libraryPath != NULL &&
+			idVendor == driverTracker[i].manuID &&
+			idProduct == driverTracker[i].productID)
+		{
+			if ((driverTracker[i].CFBundleName != NULL)
+				&& (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
+				classdriver = &driverTracker[i];
+			else
+				/* it is not a CCID Class driver */
+				driver = &driverTracker[i];
+		}
+	}
+
+	/* if we found a specific driver */
+	if (driver)
+		return driver;
+
+	/* else return the Class driver (if any) */
+	return classdriver;
+}
+
+
+static void HPAddDevice(struct udev_device *dev, struct udev_device *parent,
+	const char *devpath)
+{
+	int i;
+	char deviceName[MAX_DEVICENAME];
+	char fullname[MAX_READERNAME];
+	struct _driverTracker *driver;
+	const char *sSerialNumber = NULL, *sInterfaceName = NULL;
+	LONG ret;
+	int bInterfaceNumber;
+
+	driver = get_driver(parent, devpath);
+	if (NULL == driver)
+	{
+		/* not a smart card reader */
+#ifdef DEBUG_HOTPLUG
+		Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
+			devpath);
+#endif
+		return;
+	}
+
+	Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
+
+	bInterfaceNumber = atoi(udev_device_get_sysattr_value(dev,
+		"bInterfaceNumber"));
+	(void)snprintf(deviceName, sizeof(deviceName),
+		"usb:%04x/%04x:libudev:%d:%s", driver->manuID, driver->productID,
+		bInterfaceNumber, devpath);
+	deviceName[sizeof(deviceName) -1] = '\0';
+
+	(void)pthread_mutex_lock(&usbNotifierMutex);
+
+	/* find a free entry */
+	for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		if (NULL == readerTracker[i].fullName)
+			break;
+	}
+
+	if (PCSCLITE_MAX_READERS_CONTEXTS == i)
+	{
+		Log2(PCSC_LOG_ERROR,
+			"Not enough reader entries. Already found %d readers", i);
+		(void)pthread_mutex_unlock(&usbNotifierMutex);
+		return;
+	}
+
+#ifdef ADD_INTERFACE_NAME
+	sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
+#endif
+
+#ifdef ADD_SERIAL_NUMBER
+	sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
+#endif
+
+	/* name from the Info.plist file */
+	strlcpy(fullname, driver->readerName, sizeof(fullname));
+
+	/* interface name from the device (if any) */
+	if (sInterfaceName)
+	{
+		strlcat(fullname, " [", sizeof(fullname));
+		strlcat(fullname, sInterfaceName, sizeof(fullname));
+		strlcat(fullname, "]", sizeof(fullname));
+	}
+
+	/* serial number from the device (if any) */
+	if (sSerialNumber)
+	{
+		/* only add the serial number if it is not already present in the
+		 * interface name */
+		if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
+		{
+			strlcat(fullname, " (", sizeof(fullname));
+			strlcat(fullname, sSerialNumber, sizeof(fullname));
+			strlcat(fullname, ")", sizeof(fullname));
+		}
+	}
+
+	readerTracker[i].fullName = strdup(fullname);
+	readerTracker[i].devpath = strdup(devpath);
+	readerTracker[i].status = READER_PRESENT;
+	readerTracker[i].bInterfaceNumber = bInterfaceNumber;
+
+	ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
+		driver->libraryPath, deviceName);
+	if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
+	{
+		Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
+			driver->readerName);
+		readerTracker[i].status = READER_FAILED;
+
+		(void)CheckForOpenCT();
+	}
+
+	(void)pthread_mutex_unlock(&usbNotifierMutex);
+} /* HPAddDevice */
+
+
+static void HPRescanUsbBus(struct udev *udev)
+{
+	int i, j;
+	struct udev_enumerate *enumerate;
+	struct udev_list_entry *devices, *dev_list_entry;
+
+	/* all reader are marked absent */
+	for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
+		readerTracker[i].status = READER_ABSENT;
+
+	/* Create a list of the devices in the 'usb' subsystem. */
+	enumerate = udev_enumerate_new(udev);
+	udev_enumerate_add_match_subsystem(enumerate, "usb");
+	udev_enumerate_scan_devices(enumerate);
+	devices = udev_enumerate_get_list_entry(enumerate);
+
+	/* For each item enumerated */
+	udev_list_entry_foreach(dev_list_entry, devices)
+	{
+		const char *devpath;
+		struct udev_device *dev, *parent;
+		struct _driverTracker *driver;
+		int newreader;
+		int bInterfaceNumber;
+		const char *interface;
+
+		/* Get the filename of the /sys entry for the device
+		   and create a udev_device object (dev) representing it */
+		devpath = udev_list_entry_get_name(dev_list_entry);
+		dev = udev_device_new_from_syspath(udev, devpath);
+
+		/* The device pointed to by dev contains information about
+		   the interface. In order to get information about the USB
+		   device, get the parent device with the subsystem/devtype pair
+		   of "usb"/"usb_device". This will be several levels up the
+		   tree, but the function will find it.*/
+		parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
+			"usb_device");
+		if (!parent)
+			continue;
+
+		devpath = udev_device_get_devnode(parent);
+		driver = get_driver(parent, devpath);
+		if (NULL == driver)
+			/* no driver known for this device */
+			continue;
+
+#ifdef DEBUG_HOTPLUG
+		Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
+#endif
+
+		newreader = TRUE;
+		bInterfaceNumber = 0;
+		interface = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
+		if (interface)
+			bInterfaceNumber = atoi(interface);
+
+		/* Check if the reader is a new one */
+		for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
+		{
+			if (readerTracker[j].devpath
+				&& (strcmp(readerTracker[j].devpath, devpath) == 0)
+				&& (bInterfaceNumber == readerTracker[j].bInterfaceNumber))
+			{
+				/* The reader is already known */
+				readerTracker[j].status = READER_PRESENT;
+				newreader = FALSE;
+#ifdef DEBUG_HOTPLUG
+				Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s", devpath);
+#endif
+				break;
+			}
+		}
+
+		/* New reader found */
+		if (newreader)
+			HPAddDevice(dev, parent, devpath);
+
+		/* free device */
+		udev_device_unref(dev);
+	}
+
+	/* Free the enumerator object */
+	udev_enumerate_unref(enumerate);
+
+	/* check if all the previously found readers are still present */
+	for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		if ((READER_ABSENT == readerTracker[i].status)
+			&& (readerTracker[i].fullName != NULL))
+		{
+			pthread_mutex_lock(&usbNotifierMutex);
+
+			Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", i,
+				readerTracker[i].devpath);
+
+			RFRemoveReader(readerTracker[i].fullName,
+				PCSCLITE_HP_BASE_PORT + i);
+
+			readerTracker[i].status = READER_ABSENT;
+			free(readerTracker[i].devpath);
+			readerTracker[i].devpath = NULL;
+			free(readerTracker[i].fullName);
+			readerTracker[i].fullName = NULL;
+
+			pthread_mutex_unlock(&usbNotifierMutex);
+		}
+	}
+}
+
+static void HPEstablishUSBNotifications(struct udev *udev)
+{
+	struct udev_monitor *udev_monitor;
+	int r, i;
+
+	udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
+
+	/* filter only the interfaces */
+	r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
+		"usb_interface");
+	if (r)
+	{
+		Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
+		return;
+	}
+
+	r = udev_monitor_enable_receiving(udev_monitor);
+	if (r)
+	{
+		Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
+		return;
+	}
+
+	while (!AraKiriHotPlug)
+	{
+		struct udev_device *dev, *parent;
+		const char *action, *devpath;
+
+#ifdef DEBUG_HOTPLUG
+		Log0(PCSC_LOG_INFO);
+#endif
+
+		dev = udev_monitor_receive_device(udev_monitor);
+		if (!dev)
+		{
+			Log1(PCSC_LOG_ERROR, "udev_monitor_receive_device() error\n");
+			return;
+		}
+
+		action = udev_device_get_action(dev);
+		if (0 == strcmp("remove", action))
+		{
+			Log1(PCSC_LOG_INFO, "Device removed");
+			HPRescanUsbBus(udev);
+			continue;
+		}
+
+		if (strcmp("add", action))
+			continue;
+
+		parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
+			"usb_device");
+		devpath = udev_device_get_devnode(parent);
+
+		HPAddDevice(dev, parent, devpath);
+
+		/* free device */
+		udev_device_unref(dev);
+
+	}
+
+	for (i=0; i<driverSize; i++)
+	{
+		/* free strings allocated by strdup() */
+		free(driverTracker[i].bundleName);
+		free(driverTracker[i].libraryPath);
+		free(driverTracker[i].readerName);
+	}
+	free(driverTracker);
+
+	Log1(PCSC_LOG_INFO, "Hotplug stopped");
+} /* HPEstablishUSBNotifications */
+
+
+/***
+ * Start a thread waiting for hotplug events
+ */
+LONG HPSearchHotPluggables(void)
+{
+	int i;
+
+	for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
+	{
+		readerTracker[i].status = READER_ABSENT;
+		readerTracker[i].bInterfaceNumber = 0;
+		readerTracker[i].devpath = NULL;
+		readerTracker[i].fullName = NULL;
+	}
+
+	return HPReadBundleValues();
+} /* HPSearchHotPluggables */
+
+
+/**
+ * Stop the hotplug thread
+ */
+LONG HPStopHotPluggables(void)
+{
+	AraKiriHotPlug = TRUE;
+
+	return 0;
+} /* HPStopHotPluggables */
+
+
+/**
+ * Sets up callbacks for device hotplug events.
+ */
+ULONG HPRegisterForHotplugEvents(void)
+{
+	struct udev *udev;
+
+	(void)pthread_mutex_init(&usbNotifierMutex, NULL);
+
+	if (driverSize <= 0)
+	{
+		Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: "
+			PCSCLITE_HP_DROPDIR);
+		Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
+		return 0;
+	}
+
+	/* Create the udev object */
+	udev = udev_new();
+	if (!udev)
+	{
+		Log1(PCSC_LOG_ERROR, "udev_new() failed");
+		return 0;
+	}
+
+	HPRescanUsbBus(udev);
+
+	(void)ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
+		(PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev);
+
+	return 0;
+} /* HPRegisterForHotplugEvents */
+
+
+void HPReCheckSerialReaders(void)
+{
+	/* nothing to do here */
+#ifdef DEBUG_HOTPLUG
+	Log0(PCSC_LOG_ERROR);
+#endif
+} /* HPReCheckSerialReaders */
+
+#endif
+

Propchange: trunk/PCSC/src/hotplug_libudev.c
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: trunk/PCSC/src/hotplug_linux.c
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/hotplug_linux.c?rev=5638&op=diff
==============================================================================
--- trunk/PCSC/src/hotplug_linux.c (original)
+++ trunk/PCSC/src/hotplug_linux.c Fri Feb 25 13:36:57 2011
@@ -20,7 +20,7 @@
 #include "config.h"
 #include <string.h>
 
-#if defined(__linux__) && !defined(HAVE_LIBUSB) && !defined(HAVE_LIBHAL)
+#if defined(__linux__) && !defined(HAVE_LIBUSB) && !defined(HAVE_LIBUDEV)
 #include <sys/types.h>
 #include <stdio.h>
 #include <dirent.h>




More information about the Pcsclite-cvs-commit mailing list