pcsc-lite 1.7.2

hotplug_libusb.c

Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 2001-2004
00005  *  David Corcoran <corcoran@linuxnet.com>
00006  * Copyright (C) 2003-2010
00007  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00008  * Copyright (C) 2003
00009  *  Toni Andjelkovic <toni@soth.at>
00010  * Copyright (C) 2003-2004
00011  *  Damien Sauveron <damien.sauveron@labri.fr>
00012  *
00013  * $Id: hotplug_libusb.c 5636 2011-02-24 19:34:58Z rousseau $
00014  */
00015 
00021 #include "config.h"
00022 #ifdef HAVE_LIBUSB
00023 
00024 #include <string.h>
00025 #include <sys/types.h>
00026 #include <stdio.h>
00027 #include <dirent.h>
00028 #include <fcntl.h>
00029 #include <time.h>
00030 #include <stdlib.h>
00031 #include <unistd.h>
00032 #include <errno.h>
00033 #include <libusb.h>
00034 #include <pthread.h>
00035 
00036 #include "misc.h"
00037 #include "wintypes.h"
00038 #include "pcscd.h"
00039 #include "debuglog.h"
00040 #include "parser.h"
00041 #include "readerfactory.h"
00042 #include "winscard_msg.h"
00043 #include "sys_generic.h"
00044 #include "hotplug.h"
00045 #include "utils.h"
00046 
00047 #undef DEBUG_HOTPLUG
00048 #define ADD_SERIAL_NUMBER
00049 
00050 /* format is "%d:%d:%d", bus_number, device_address, interface */
00051 #define BUS_DEVICE_STRSIZE  10+1+10+1+10+1
00052 
00053 #define READER_ABSENT       0
00054 #define READER_PRESENT      1
00055 #define READER_FAILED       2
00056 
00057 #define FALSE           0
00058 #define TRUE            1
00059 
00060 /* we use the default libusb context */
00061 #define ctx NULL
00062 
00063 pthread_mutex_t usbNotifierMutex;
00064 
00065 static pthread_t usbNotifyThread;
00066 static int driverSize = -1;
00067 static char AraKiriHotPlug = FALSE;
00068 static int rescan_pipe[] = { -1, -1 };
00069 extern int HPForceReaderPolling;
00070 
00071 /* values of ifdCapabilities bits */
00072 #define IFD_GENERATE_HOTPLUG 1
00073 
00077 static struct _driverTracker
00078 {
00079     unsigned int manuID;
00080     unsigned int productID;
00081 
00082     char *bundleName;
00083     char *libraryPath;
00084     char *readerName;
00085     int ifdCapabilities;
00086 } *driverTracker = NULL;
00087 #define DRIVER_TRACKER_SIZE_STEP 8
00088 
00092 static struct _readerTracker
00093 {
00094     char status;
00095     char bus_device[BUS_DEVICE_STRSIZE];    
00096     char *fullName; 
00097 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
00098 
00099 static LONG HPAddHotPluggable(struct libusb_device *dev,
00100     struct libusb_device_descriptor desc,
00101     const char bus_device[], int interface,
00102     struct _driverTracker *driver);
00103 static LONG HPRemoveHotPluggable(int reader_index);
00104 
00105 static LONG HPReadBundleValues(void)
00106 {
00107     LONG rv;
00108     DIR *hpDir;
00109     struct dirent *currFP = NULL;
00110     char fullPath[FILENAME_MAX];
00111     char fullLibPath[FILENAME_MAX];
00112     int listCount = 0;
00113 
00114     hpDir = opendir(PCSCLITE_HP_DROPDIR);
00115 
00116     if (hpDir == NULL)
00117     {
00118         Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
00119         Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
00120         return -1;
00121     }
00122 
00123     /* allocate a first array */
00124     driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
00125     if (NULL == driverTracker)
00126     {
00127         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00128         return -1;
00129     }
00130     driverSize = DRIVER_TRACKER_SIZE_STEP;
00131 
00132 #define GET_KEY(key, values) \
00133     rv = LTPBundleFindValueWithKey(&plist, key, values); \
00134     if (rv) \
00135     { \
00136         Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
00137             fullPath); \
00138         continue; \
00139     }
00140 
00141     while ((currFP = readdir(hpDir)) != 0)
00142     {
00143         if (strstr(currFP->d_name, ".bundle") != 0)
00144         {
00145             unsigned int alias;
00146             list_t plist, *values;
00147             list_t *manuIDs, *productIDs, *readerNames;
00148             char *libraryPath;
00149             int ifdCapabilities;
00150 
00151             /*
00152              * The bundle exists - let's form a full path name and get the
00153              * vendor and product ID's for this particular bundle
00154              */
00155             snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
00156                 PCSCLITE_HP_DROPDIR, currFP->d_name);
00157             fullPath[sizeof(fullPath) - 1] = '\0';
00158 
00159             rv = bundleParse(fullPath, &plist);
00160             if (rv)
00161                 continue;
00162 
00163             /* get CFBundleExecutable */
00164             GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
00165             libraryPath = list_get_at(values, 0);
00166             (void)snprintf(fullLibPath, sizeof(fullLibPath),
00167                 "%s/%s/Contents/%s/%s",
00168                 PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
00169                 libraryPath);
00170             fullLibPath[sizeof(fullLibPath) - 1] = '\0';
00171 
00172             /* Get ifdCapabilities */
00173             GET_KEY(PCSCLITE_HP_CPCTKEY_NAME, &values)
00174             ifdCapabilities = strtol(list_get_at(values, 0), NULL, 16);
00175 
00176             GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
00177             GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
00178             GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
00179 
00180             /* while we find a nth ifdVendorID in Info.plist */
00181             for (alias=0; alias<list_size(manuIDs); alias++)
00182             {
00183                 char *value;
00184 
00185                 /* variables entries */
00186                 value = list_get_at(manuIDs, alias);
00187                 driverTracker[listCount].manuID = strtol(value, NULL, 16);
00188 
00189                 value = list_get_at(productIDs, alias);
00190                 driverTracker[listCount].productID = strtol(value, NULL, 16);
00191 
00192                 driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
00193 
00194                 /* constant entries for a same driver */
00195                 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00196                 driverTracker[listCount].libraryPath = strdup(fullLibPath);
00197                 driverTracker[listCount].ifdCapabilities = ifdCapabilities;
00198 
00199 #ifdef DEBUG_HOTPLUG
00200                 Log2(PCSC_LOG_INFO, "Found driver for: %s",
00201                     driverTracker[listCount].readerName);
00202 #endif
00203                 listCount++;
00204                 if (listCount >= driverSize)
00205                 {
00206                     int i;
00207 
00208                     /* increase the array size */
00209                     driverSize += DRIVER_TRACKER_SIZE_STEP;
00210 #ifdef DEBUG_HOTPLUG
00211                     Log2(PCSC_LOG_INFO,
00212                         "Increase driverTracker to %d entries", driverSize);
00213 #endif
00214                     driverTracker = realloc(driverTracker,
00215                         driverSize * sizeof(*driverTracker));
00216                     if (NULL == driverTracker)
00217                     {
00218                         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00219                         driverSize = -1;
00220                         return -1;
00221                     }
00222 
00223                     /* clean the newly allocated entries */
00224                     for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
00225                     {
00226                         driverTracker[i].manuID = 0;
00227                         driverTracker[i].productID = 0;
00228                         driverTracker[i].bundleName = NULL;
00229                         driverTracker[i].libraryPath = NULL;
00230                         driverTracker[i].readerName = NULL;
00231                         driverTracker[i].ifdCapabilities = 0;
00232                     }
00233                 }
00234             }
00235             bundleRelease(&plist);
00236         }
00237     }
00238 
00239     driverSize = listCount;
00240     closedir(hpDir);
00241 
00242     rv = TRUE;
00243     if (driverSize == 0)
00244     {
00245         Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
00246         Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
00247         rv = FALSE;
00248     }
00249 #ifdef DEBUG_HOTPLUG
00250     else
00251         Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
00252 #endif
00253 
00254     return rv;
00255 }
00256 
00257 static void HPRescanUsbBus(void)
00258 {
00259     int i, j;
00260     char bus_device[BUS_DEVICE_STRSIZE];
00261     libusb_device **devs, *dev;
00262     ssize_t cnt;
00263 
00264     for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00265         /* clear rollcall */
00266         readerTracker[i].status = READER_ABSENT;
00267 
00268     cnt = libusb_get_device_list(ctx, &devs);
00269     if (cnt < 0)
00270     {
00271         Log1(PCSC_LOG_CRITICAL, "libusb_get_device_list() failed\n");
00272         return;
00273     }
00274 
00275     /* For each USB device */
00276     cnt = 0;
00277     while ((dev = devs[cnt++]) != NULL)
00278     {
00279         struct libusb_device_descriptor desc;
00280         struct libusb_config_descriptor *config_desc;
00281         uint8_t bus_number = libusb_get_bus_number(dev);
00282         uint8_t device_address = libusb_get_device_address(dev);
00283 
00284         int r = libusb_get_device_descriptor(dev, &desc);
00285         if (r < 0)
00286         {
00287             Log3(PCSC_LOG_ERROR, "failed to get device descriptor for %d/%d",
00288                 bus_number, device_address);
00289             continue;
00290         }
00291 
00292         r = libusb_get_active_config_descriptor(dev, &config_desc);
00293         if (r < 0)
00294         {
00295             Log3(PCSC_LOG_ERROR, "failed to get device config for %d/%d",
00296                 bus_number, device_address);
00297             continue;
00298         }
00299 
00300         /* check if the device is supported by one driver */
00301         for (i=0; i<driverSize; i++)
00302         {
00303             if (driverTracker[i].libraryPath != NULL &&
00304                 desc.idVendor == driverTracker[i].manuID &&
00305                 desc.idProduct == driverTracker[i].productID)
00306             {
00307                 int interface;
00308 
00309 #ifdef DEBUG_HOTPLUG
00310                 Log3(PCSC_LOG_DEBUG, "Found matching USB device: %d:%d",
00311                     bus_number, device_address);
00312 #endif
00313 
00314                 for (interface = 0; interface < config_desc->bNumInterfaces;
00315                     interface++)
00316                 {
00317                     int newreader;
00318 
00319                     /* A known device has been found */
00320                     snprintf(bus_device, BUS_DEVICE_STRSIZE, "%d:%d:%d",
00321                          bus_number, device_address, interface);
00322                     bus_device[BUS_DEVICE_STRSIZE - 1] = '\0';
00323                     newreader = TRUE;
00324 
00325                     /* Check if the reader is a new one */
00326                     for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
00327                     {
00328                         if (strncmp(readerTracker[j].bus_device,
00329                             bus_device, BUS_DEVICE_STRSIZE) == 0)
00330                         {
00331                             /* The reader is already known */
00332                             readerTracker[j].status = READER_PRESENT;
00333                             newreader = FALSE;
00334 #ifdef DEBUG_HOTPLUG
00335                             Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s",
00336                                 bus_device);
00337 #endif
00338                             break;
00339                         }
00340                     }
00341 
00342                     /* New reader found */
00343                     if (newreader)
00344                     {
00345                         if (config_desc->bNumInterfaces > 1)
00346                             HPAddHotPluggable(dev, desc, bus_device,
00347                                 interface, &driverTracker[i]);
00348                             else
00349                             HPAddHotPluggable(dev, desc, bus_device,
00350                                 -1, &driverTracker[i]);
00351                     }
00352                 }
00353             }
00354         }
00355     }
00356 
00357     /*
00358      * check if all the previously found readers are still present
00359      */
00360     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00361     {
00362         if ((readerTracker[i].status == READER_ABSENT) &&
00363             (readerTracker[i].fullName != NULL))
00364             HPRemoveHotPluggable(i);
00365     }
00366 
00367     if (AraKiriHotPlug)
00368     {
00369         int retval;
00370 
00371         for (i=0; i<driverSize; i++)
00372         {
00373             /* free strings allocated by strdup() */
00374             free(driverTracker[i].bundleName);
00375             free(driverTracker[i].libraryPath);
00376             free(driverTracker[i].readerName);
00377         }
00378         free(driverTracker);
00379 
00380         Log1(PCSC_LOG_INFO, "Hotplug stopped");
00381         pthread_exit(&retval);
00382     }
00383 
00384     /* free the libusb allocated list & devices */
00385     libusb_free_device_list(devs, 1);
00386 }
00387 
00388 static void HPEstablishUSBNotifications(int pipefd[2])
00389 {
00390     int i, do_polling;
00391     char c = 42;    /* magic value */
00392 
00393     libusb_init(ctx);
00394 
00395     /* scan the USB bus for devices at startup */
00396     HPRescanUsbBus();
00397 
00398     /* signal that the initially connected readers are now visible */
00399     write(pipefd[1], &c, 1);
00400     close(pipefd[1]);
00401 
00402     /* if at least one driver do not have IFD_GENERATE_HOTPLUG */
00403     do_polling = FALSE;
00404     for (i=0; i<driverSize; i++)
00405         if (driverTracker[i].libraryPath)
00406             if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0)
00407             {
00408                 Log2(PCSC_LOG_INFO,
00409                     "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.",
00410                     driverTracker[i].bundleName);
00411                 if (HPForceReaderPolling < 1)
00412                     HPForceReaderPolling = 1;
00413                 break;
00414             }
00415 
00416     if (HPForceReaderPolling)
00417     {
00418         Log2(PCSC_LOG_INFO,
00419                 "Polling forced every %d second(s)", HPForceReaderPolling);
00420         do_polling = TRUE;
00421     }
00422 
00423     if (do_polling)
00424     {
00425         while (!AraKiriHotPlug)
00426         {
00427             SYS_Sleep(HPForceReaderPolling);
00428             HPRescanUsbBus();
00429         }
00430     }
00431     else
00432     {
00433         char dummy;
00434 
00435         pipe(rescan_pipe);
00436         while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0)
00437         {
00438             Log1(PCSC_LOG_INFO, "Reload serial configuration");
00439             HPRescanUsbBus();
00440 #ifdef USE_SERIAL
00441             RFReCheckReaderConf();
00442 #endif
00443             Log1(PCSC_LOG_INFO, "End reload serial configuration");
00444         }
00445         close(rescan_pipe[0]);
00446         rescan_pipe[0] = -1;
00447     }
00448 }
00449 
00450 LONG HPSearchHotPluggables(void)
00451 {
00452     int i;
00453 
00454     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00455     {
00456         readerTracker[i].status = READER_ABSENT;
00457         readerTracker[i].bus_device[0] = '\0';
00458         readerTracker[i].fullName = NULL;
00459     }
00460 
00461     if (HPReadBundleValues())
00462     {
00463         int pipefd[2];
00464         char c;
00465 
00466         if (pipe(pipefd) == -1)
00467         {
00468             Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
00469             return -1;
00470         }
00471 
00472         ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
00473             (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd);
00474 
00475         /* Wait for initial readers to setup */
00476         read(pipefd[0], &c, 1);
00477         close(pipefd[0]);
00478     }
00479 
00480     return 0;
00481 }
00482 
00483 LONG HPStopHotPluggables(void)
00484 {
00485     AraKiriHotPlug = TRUE;
00486     if (rescan_pipe[1] >= 0)
00487     {
00488         close(rescan_pipe[1]);
00489         rescan_pipe[1] = -1;
00490     }
00491 
00492     return 0;
00493 }
00494 
00495 static LONG HPAddHotPluggable(struct libusb_device *dev,
00496     struct libusb_device_descriptor desc,
00497     const char bus_device[], int interface,
00498     struct _driverTracker *driver)
00499 {
00500     int i;
00501     char deviceName[MAX_DEVICENAME];
00502 
00503     Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
00504 
00505     if (interface >= 0)
00506         snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libhal:/org/freedesktop/Hal/devices/usb_device_%04x_%04x_serialnotneeded_if%d",
00507              desc.idVendor, desc.idProduct, desc.idVendor, desc.idProduct,
00508              interface);
00509     else
00510         snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb-1.0:%s",
00511             desc.idVendor, desc.idProduct, bus_device);
00512 
00513     deviceName[sizeof(deviceName) -1] = '\0';
00514 
00515     pthread_mutex_lock(&usbNotifierMutex);
00516 
00517     /* find a free entry */
00518     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00519     {
00520         if (readerTracker[i].fullName == NULL)
00521             break;
00522     }
00523 
00524     if (i==PCSCLITE_MAX_READERS_CONTEXTS)
00525     {
00526         Log2(PCSC_LOG_ERROR,
00527             "Not enough reader entries. Already found %d readers", i);
00528         pthread_mutex_unlock(&usbNotifierMutex);
00529         return 0;
00530     }
00531 
00532     strncpy(readerTracker[i].bus_device, bus_device,
00533         sizeof(readerTracker[i].bus_device));
00534     readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0';
00535 
00536 #ifdef ADD_SERIAL_NUMBER
00537     if (desc.iSerialNumber)
00538     {
00539         libusb_device_handle *device;
00540         unsigned char serialNumber[MAX_READERNAME];
00541         char fullname[MAX_READERNAME];
00542         int ret;
00543 
00544         ret = libusb_open(dev, &device);
00545         if (ret < 0)
00546         {
00547             Log2(PCSC_LOG_ERROR, "libusb_open failed: %d", ret);
00548         }
00549         else
00550         {
00551             ret = libusb_get_string_descriptor_ascii(device, desc.iSerialNumber,
00552                 serialNumber, MAX_READERNAME);
00553             libusb_close(device);
00554 
00555             if (ret < 0)
00556             {
00557                 Log2(PCSC_LOG_ERROR,
00558                     "libusb_get_string_descriptor_ascii failed: %d", ret);
00559                 readerTracker[i].fullName = strdup(driver->readerName);
00560             }
00561             else
00562             {
00563                 snprintf(fullname, sizeof(fullname), "%s (%s)",
00564                     driver->readerName, serialNumber);
00565                 readerTracker[i].fullName = strdup(fullname);
00566             }
00567         }
00568     }
00569     else
00570 #endif
00571         readerTracker[i].fullName = strdup(driver->readerName);
00572 
00573     if (RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
00574         driver->libraryPath, deviceName) == SCARD_S_SUCCESS)
00575         readerTracker[i].status = READER_PRESENT;
00576     else
00577     {
00578         readerTracker[i].status = READER_FAILED;
00579 
00580         (void)CheckForOpenCT();
00581     }
00582 
00583     pthread_mutex_unlock(&usbNotifierMutex);
00584 
00585     return 1;
00586 }   /* End of function */
00587 
00588 static LONG HPRemoveHotPluggable(int reader_index)
00589 {
00590     pthread_mutex_lock(&usbNotifierMutex);
00591 
00592     Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index,
00593         readerTracker[reader_index].bus_device);
00594 
00595     RFRemoveReader(readerTracker[reader_index].fullName,
00596         PCSCLITE_HP_BASE_PORT + reader_index);
00597     free(readerTracker[reader_index].fullName);
00598     readerTracker[reader_index].status = READER_ABSENT;
00599     readerTracker[reader_index].bus_device[0] = '\0';
00600     readerTracker[reader_index].fullName = NULL;
00601 
00602     pthread_mutex_unlock(&usbNotifierMutex);
00603 
00604     return 1;
00605 }   /* End of function */
00606 
00610 ULONG HPRegisterForHotplugEvents(void)
00611 {
00612     (void)pthread_mutex_init(&usbNotifierMutex, NULL);
00613     return 0;
00614 }
00615 
00616 void HPReCheckSerialReaders(void)
00617 {
00618     if (rescan_pipe[1] >= 0)
00619     {
00620         char dummy = 0;
00621         write(rescan_pipe[1], &dummy, sizeof(dummy));
00622     }
00623 }
00624 
00625 #endif
00626