hotplug_libhal.c

Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 2008
00005  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00006  *
00007  * $Id: hotplug_libhal.c 3304 2009-02-06 08:46:19Z rousseau $
00008  */
00009 
00015 #include "config.h"
00016 #ifdef HAVE_LIBHAL
00017 
00018 #include <string.h>
00019 #include <stdio.h>
00020 #include <dirent.h>
00021 #include <stdlib.h>
00022 #include <libhal.h>
00023 
00024 #include "misc.h"
00025 #include "wintypes.h"
00026 #include "pcscd.h"
00027 #include "debuglog.h"
00028 #include "parser.h"
00029 #include "readerfactory.h"
00030 #include "sys_generic.h"
00031 #include "hotplug.h"
00032 #include "thread_generic.h"
00033 #include "utils.h"
00034 
00035 #undef DEBUG_HOTPLUG
00036 #define ADD_SERIAL_NUMBER
00037 
00038 #define FALSE           0
00039 #define TRUE            1
00040 
00041 #define UDI_BASE "/org/freedesktop/Hal/devices/"
00042 
00043 extern PCSCLITE_MUTEX usbNotifierMutex;
00044 
00045 static PCSCLITE_THREAD_T usbNotifyThread;
00046 static int driverSize = -1;
00047 static char AraKiriHotPlug = FALSE;
00048 
00049 static DBusConnection *conn;
00050 static LibHalContext *hal_ctx;
00051 
00055 static struct _driverTracker
00056 {
00057     unsigned int manuID;
00058     unsigned int productID;
00059 
00060     char *bundleName;
00061     char *libraryPath;
00062     char *readerName;
00063     int ifdCapabilities;
00064 } *driverTracker = NULL;
00065 #define DRIVER_TRACKER_SIZE_STEP 8
00066 
00070 static struct _readerTracker
00071 {
00072     char *udi;  
00073     char *fullName; 
00074 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
00075 
00076 static LONG HPReadBundleValues(void);
00077 static void HPAddDevice(LibHalContext *ctx, const char *udi);
00078 static void HPRemoveDevice(LibHalContext *ctx, const char *udi);
00079 static void HPEstablishUSBNotifications(void);
00080 
00086 static const char *short_name(const char *udi)
00087 {
00088     return &udi[sizeof(UDI_BASE) - 1];
00089 } /* short_name */
00090 
00091 
00092 static LONG HPReadBundleValues(void)
00093 {
00094     LONG rv;
00095     DIR *hpDir;
00096     struct dirent *currFP = NULL;
00097     char fullPath[FILENAME_MAX];
00098     char fullLibPath[FILENAME_MAX];
00099     char keyValue[TOKEN_MAX_VALUE_SIZE];
00100     int listCount = 0;
00101 
00102     hpDir = opendir(PCSCLITE_HP_DROPDIR);
00103 
00104     if (NULL == hpDir)
00105     {
00106         Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
00107         Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
00108         return -1;
00109     }
00110 
00111     /* allocate a first array */
00112     driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
00113     if (NULL == driverTracker)
00114     {
00115         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00116         return -1;
00117     }
00118     driverSize = DRIVER_TRACKER_SIZE_STEP;
00119 
00120     while ((currFP = readdir(hpDir)) != 0)
00121     {
00122         if (strstr(currFP->d_name, ".bundle") != 0)
00123         {
00124             int alias = 0;
00125 
00126             /*
00127              * The bundle exists - let's form a full path name and get the
00128              * vendor and product ID's for this particular bundle
00129              */
00130             (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
00131                 PCSCLITE_HP_DROPDIR, currFP->d_name);
00132             fullPath[sizeof(fullPath) - 1] = '\0';
00133 
00134             /* while we find a nth ifdVendorID in Info.plist */
00135             while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
00136                 keyValue, alias) == 0)
00137             {
00138                 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00139 
00140                 /* Get ifdVendorID */
00141                 rv = LTPBundleFindValueWithKey(fullPath,
00142                     PCSCLITE_HP_MANUKEY_NAME, keyValue, alias);
00143                 if (0 == rv)
00144                     driverTracker[listCount].manuID = strtol(keyValue, NULL, 16);
00145 
00146                 /* get ifdProductID */
00147                 rv = LTPBundleFindValueWithKey(fullPath,
00148                     PCSCLITE_HP_PRODKEY_NAME, keyValue, alias);
00149                 if (0 == rv)
00150                     driverTracker[listCount].productID =
00151                         strtol(keyValue, NULL, 16);
00152 
00153                 /* get ifdFriendlyName */
00154                 rv = LTPBundleFindValueWithKey(fullPath,
00155                     PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias);
00156                 if (0 == rv)
00157                     driverTracker[listCount].readerName = strdup(keyValue);
00158 
00159                 /* get CFBundleExecutable */
00160                 rv = LTPBundleFindValueWithKey(fullPath,
00161                     PCSCLITE_HP_LIBRKEY_NAME, keyValue, 0);
00162                 if (0 == rv)
00163                 {
00164                     (void)snprintf(fullLibPath, sizeof(fullLibPath),
00165                         "%s/%s/Contents/%s/%s",
00166                         PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
00167                         keyValue);
00168                     fullLibPath[sizeof(fullLibPath) - 1] = '\0';
00169                     driverTracker[listCount].libraryPath = strdup(fullLibPath);
00170                 }
00171 
00172                 /* Get ifdCapabilities */
00173                 rv = LTPBundleFindValueWithKey(fullPath,
00174                     PCSCLITE_HP_CPCTKEY_NAME, keyValue, 0);
00175                 if (0 == rv)
00176                     driverTracker[listCount].ifdCapabilities = strtol(keyValue,
00177                         NULL, 16);
00178 
00179 #ifdef DEBUG_HOTPLUG
00180                 Log2(PCSC_LOG_INFO, "Found driver for: %s",
00181                     driverTracker[listCount].readerName);
00182 #endif
00183                 alias++;
00184 
00185                 if (NULL == driverTracker[listCount].readerName)
00186                     continue;
00187 
00188                 listCount++;
00189                 if (listCount >= driverSize)
00190                 {
00191                     int i;
00192 
00193                     /* increase the array size */
00194                     driverSize += DRIVER_TRACKER_SIZE_STEP;
00195 #ifdef DEBUG_HOTPLUG
00196                     Log2(PCSC_LOG_INFO,
00197                         "Increase driverTracker to %d entries", driverSize);
00198 #endif
00199                     driverTracker = realloc(driverTracker,
00200                         driverSize * sizeof(*driverTracker));
00201                     if (NULL == driverTracker)
00202                     {
00203                         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00204                         driverSize = -1;
00205                         return -1;
00206                     }
00207 
00208                     /* clean the newly allocated entries */
00209                     for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
00210                     {
00211                         driverTracker[i].manuID = 0;
00212                         driverTracker[i].productID = 0;
00213                         driverTracker[i].bundleName = NULL;
00214                         driverTracker[i].libraryPath = NULL;
00215                         driverTracker[i].readerName = NULL;
00216                         driverTracker[i].ifdCapabilities = 0;
00217                     }
00218                 }
00219             }
00220         }
00221     }
00222 
00223     driverSize = listCount;
00224     (void)closedir(hpDir);
00225 
00226 #ifdef DEBUG_HOTPLUG
00227     Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
00228 #endif
00229 
00230     return 0;
00231 } /* HPReadBundleValues */
00232 
00233 
00234 void HPEstablishUSBNotifications(void)
00235 {
00236     while (!AraKiriHotPlug && dbus_connection_read_write_dispatch(conn, -1))
00237     {
00238 #ifdef DEBUG_HOTPLUG
00239         Log0(PCSC_LOG_INFO);
00240 #endif
00241     }
00242 } /* HPEstablishUSBNotifications */
00243 
00244 
00245 /***
00246  * Start a thread waiting for hotplug events
00247  */
00248 LONG HPSearchHotPluggables(void)
00249 {
00250     int i;
00251 
00252     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00253     {
00254         readerTracker[i].udi = NULL;
00255         readerTracker[i].fullName = NULL;
00256     }
00257 
00258     return HPReadBundleValues();
00259 } /* HPSearchHotPluggables */
00260 
00261 
00265 LONG HPStopHotPluggables(void)
00266 {
00267     AraKiriHotPlug = TRUE;
00268 
00269     return 0;
00270 } /* HPStopHotPluggables */
00271 
00272 
00273 /*@null@*/ static struct _driverTracker *get_driver(LibHalContext *ctx,
00274     const char *udi)
00275 {
00276     DBusError error;
00277     int i;
00278     unsigned int idVendor, idProduct;
00279 
00280     if (!libhal_device_property_exists(ctx, udi, "usb.vendor_id", NULL))
00281         return NULL;
00282 
00283     dbus_error_init(&error);
00284 
00285     /* Vendor ID */
00286     idVendor = libhal_device_get_property_int(ctx, udi,
00287         "usb.vendor_id", &error);
00288     if (dbus_error_is_set(&error))
00289     {
00290         Log3(PCSC_LOG_ERROR, "libhal_device_get_property_int %s: %d",
00291             error.name, error.message);
00292         dbus_error_free(&error);
00293         return NULL;
00294     }
00295 
00296     /* Product ID */
00297     idProduct = libhal_device_get_property_int(ctx, udi,
00298         "usb.product_id", &error);
00299     if (dbus_error_is_set(&error))
00300     {
00301         Log3(PCSC_LOG_ERROR, "libhal_device_get_property_int %s: %d",
00302             error.name, error.message);
00303         dbus_error_free(&error);
00304         return NULL;
00305     }
00306 
00307     Log3(PCSC_LOG_DEBUG, "Looking a driver for VID: 0x%04X, PID: 0x%04X", idVendor, idProduct);
00308 
00309     /* check if the device is supported by one driver */
00310     for (i=0; i<driverSize; i++)
00311     {
00312         if (driverTracker[i].libraryPath != NULL &&
00313             idVendor == driverTracker[i].manuID &&
00314             idProduct == driverTracker[i].productID)
00315         {
00316             return &driverTracker[i];
00317         }
00318     }
00319 
00320     return NULL;
00321 }
00322 
00323 
00324 static void HPAddDevice(LibHalContext *ctx, const char *udi)
00325 {
00326     int i;
00327     char deviceName[MAX_DEVICENAME];
00328     DBusError error;
00329     struct _driverTracker *driver;
00330     LONG ret;
00331 
00332     driver = get_driver(ctx, udi);
00333     if (NULL == driver)
00334     {
00335         /* not a smart card reader */
00336 #ifdef DEBUG_HOTPLUG
00337         Log2(PCSC_LOG_DEBUG, "%s is not a reader", short_name(udi));
00338 #endif
00339         return;
00340     }
00341 
00342     Log2(PCSC_LOG_INFO, "Adding USB device: %s", short_name(udi));
00343 
00344     (void)snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libhal:%s",
00345         driver->manuID, driver->productID, udi);
00346     deviceName[sizeof(deviceName) -1] = '\0';
00347 
00348     /* wait until the device is visible by libusb/etc.  */
00349     (void)SYS_Sleep(1);
00350 
00351     (void)SYS_MutexLock(&usbNotifierMutex);
00352 
00353     /* find a free entry */
00354     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00355     {
00356         if (NULL == readerTracker[i].fullName)
00357             break;
00358     }
00359 
00360     if (PCSCLITE_MAX_READERS_CONTEXTS == i)
00361     {
00362         Log2(PCSC_LOG_ERROR,
00363             "Not enough reader entries. Already found %d readers", i);
00364         (void)SYS_MutexUnLock(&usbNotifierMutex);
00365         return;
00366     }
00367 
00368     readerTracker[i].udi = strdup(udi);
00369 
00370 #ifdef ADD_SERIAL_NUMBER
00371     dbus_error_init (&error);
00372 
00373     if (libhal_device_property_exists(ctx, udi, "usb.serial", &error))
00374     {
00375         char fullname[MAX_READERNAME];
00376         char *sSerialNumber;
00377 
00378         sSerialNumber = libhal_device_get_property_string(ctx, udi,
00379             "usb.serial", &error);
00380 
00381         (void)snprintf(fullname, sizeof(fullname), "%s (%s)",
00382             driver->readerName, sSerialNumber);
00383         readerTracker[i].fullName = strdup(fullname);
00384     }
00385     else
00386 #endif
00387         readerTracker[i].fullName = strdup(driver->readerName);
00388 #ifdef ADD_SERIAL_NUMBER
00389     if (dbus_error_is_set(&error))
00390         dbus_error_free(&error);
00391 #endif
00392 
00393     ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
00394         driver->libraryPath, deviceName);
00395     if (SCARD_S_SUCCESS != ret)
00396     {
00397         Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s", short_name(udi));
00398         free(readerTracker[i].fullName);
00399         readerTracker[i].fullName = NULL;
00400         free(readerTracker[i].udi);
00401         readerTracker[i].udi = NULL;
00402 
00403         (void)CheckForOpenCT();
00404     }
00405 
00406     (void)SYS_MutexUnLock(&usbNotifierMutex);
00407 } /* HPAddDevice */
00408 
00409 
00410 static void HPRemoveDevice(/*@unused@*/ LibHalContext *ctx, const char *udi)
00411 {
00412     int i;
00413 
00414     (void)ctx;
00415     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00416     {
00417         if (readerTracker[i].udi && strcmp(readerTracker[i].udi, udi) == 0)
00418             break;
00419     }
00420     if (PCSCLITE_MAX_READERS_CONTEXTS == i)
00421     {
00422 #ifdef DEBUG_HOTPLUG
00423         Log2(PCSC_LOG_DEBUG, "USB device %s not already used", short_name(udi));
00424 #endif
00425         return;
00426     }
00427     Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", i,
00428         short_name(readerTracker[i].udi));
00429 
00430     (void)SYS_MutexLock(&usbNotifierMutex);
00431 
00432     (void)RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i);
00433     free(readerTracker[i].fullName);
00434     readerTracker[i].fullName = NULL;
00435     free(readerTracker[i].udi);
00436     readerTracker[i].udi = NULL;
00437 
00438     (void)SYS_MutexUnLock(&usbNotifierMutex);
00439 
00440     return;
00441 } /* HPRemoveDevice */
00442 
00443 
00447 ULONG HPRegisterForHotplugEvents(void)
00448 {
00449     char **device_names;
00450     int i, num_devices;
00451     DBusError error;
00452 
00453     if (driverSize <= 0)
00454     {
00455         Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
00456         Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
00457         return 1;
00458     }
00459 
00460     dbus_error_init(&error);
00461     conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
00462     if (conn == NULL)
00463     {
00464         Log3(PCSC_LOG_ERROR, "error: dbus_bus_get: %s: %s",
00465             error.name, error.message);
00466         if (dbus_error_is_set(&error))
00467             dbus_error_free(&error);
00468         return 1;
00469     }
00470 
00471     if ((hal_ctx = libhal_ctx_new()) == NULL)
00472     {
00473         Log1(PCSC_LOG_ERROR, "error: libhal_ctx_new");
00474         return 1;
00475     }
00476     if (!libhal_ctx_set_dbus_connection(hal_ctx, conn))
00477     {
00478         Log1(PCSC_LOG_ERROR, "error: libhal_ctx_set_dbus_connection");
00479         return 1;
00480     }
00481     if (!libhal_ctx_init(hal_ctx, &error))
00482     {
00483         if (dbus_error_is_set(&error))
00484         {
00485             Log3(PCSC_LOG_ERROR, "error: libhal_ctx_init: %s: %s",
00486                 error.name, error.message);
00487             if (dbus_error_is_set(&error))
00488                 dbus_error_free(&error);
00489         }
00490         Log1(PCSC_LOG_ERROR, "Could not initialise connection to hald.");
00491         Log1(PCSC_LOG_ERROR, "Normally this means the HAL daemon (hald) is not running or not ready.");
00492         return 1;
00493     }
00494 
00495     /* callback when device added */
00496     (void)libhal_ctx_set_device_added(hal_ctx, HPAddDevice);
00497 
00498     /* callback when device removed */
00499     (void)libhal_ctx_set_device_removed(hal_ctx, HPRemoveDevice);
00500 
00501     device_names = libhal_get_all_devices(hal_ctx, &num_devices, &error);
00502     if (device_names == NULL)
00503     {
00504         if (dbus_error_is_set(&error))
00505             dbus_error_free(&error);
00506         Log1(PCSC_LOG_ERROR, "Couldn't obtain list of devices");
00507         return 1;
00508     }
00509 
00510     /* try to add every present USB devices */
00511     for (i = 0; i < num_devices; i++)
00512         HPAddDevice(hal_ctx, device_names[i]);
00513 
00514     libhal_free_string_array(device_names);
00515 
00516     (void)SYS_ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
00517         (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, NULL);
00518 
00519     return 0;
00520 } /* HPRegisterForHotplugEvents */
00521 
00522 
00523 void HPReCheckSerialReaders(void)
00524 {
00525     /* nothing to do here */
00526 #ifdef DEBUG_HOTPLUG
00527     Log0(PCSC_LOG_ERROR);
00528 #endif
00529 } /* HPReCheckSerialReaders */
00530 
00531 #endif
00532 

Generated on Mon Aug 17 01:00:09 2009 for pcsc-lite by  doxygen 1.5.9