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
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 }
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
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
00127
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
00134 while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
00135 keyValue, alias) == 0)
00136 {
00137 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00138
00139
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
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
00153 rv = LTPBundleFindValueWithKey(fullPath,
00154 PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias);
00155 if (0 == rv)
00156 driverTracker[listCount].readerName = strdup(keyValue);
00157
00158
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
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
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
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 }
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 }
00242
00243
00244
00245
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 }
00259
00260
00264 LONG HPStopHotPluggables(void)
00265 {
00266 AraKiriHotPlug = TRUE;
00267
00268 return 0;
00269 }
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
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
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
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
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
00349 SYS_Sleep(1);
00350
00351 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 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 }
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 }
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
00491 libhal_ctx_set_device_added(hal_ctx, HPAddDevice);
00492
00493
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
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 }
00516
00517
00518 void HPReCheckSerialReaders(void)
00519 {
00520
00521 #ifdef DEBUG_HOTPLUG
00522 Log0(PCSC_LOG_ERROR);
00523 #endif
00524 }
00525
00526 #endif
00527