00001
00002
00003
00004
00005
00006
00007
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 }
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
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
00128
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
00135 while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
00136 keyValue, alias) == 0)
00137 {
00138 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00139
00140
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
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
00154 rv = LTPBundleFindValueWithKey(fullPath,
00155 PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias);
00156 if (0 == rv)
00157 driverTracker[listCount].readerName = strdup(keyValue);
00158
00159
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
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
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
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 }
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 }
00243
00244
00245
00246
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 }
00260
00261
00265 LONG HPStopHotPluggables(void)
00266 {
00267 AraKiriHotPlug = TRUE;
00268
00269 return 0;
00270 }
00271
00272
00273 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
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
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
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
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
00349 (void)SYS_Sleep(1);
00350
00351 (void)SYS_MutexLock(&usbNotifierMutex);
00352
00353
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 }
00408
00409
00410 static void HPRemoveDevice( 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 }
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
00496 (void)libhal_ctx_set_device_added(hal_ctx, HPAddDevice);
00497
00498
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
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 }
00521
00522
00523 void HPReCheckSerialReaders(void)
00524 {
00525
00526 #ifdef DEBUG_HOTPLUG
00527 Log0(PCSC_LOG_ERROR);
00528 #endif
00529 }
00530
00531 #endif
00532