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

Generated on Thu Aug 28 20:14:58 2008 for pcsc-lite by  doxygen 1.5.6