pcsc-lite  1.7.4
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-2011
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 5711 2011-05-05 09:02:08Z 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         libusb_free_config_descriptor(config_desc);
00356     }
00357 
00358     /*
00359      * check if all the previously found readers are still present
00360      */
00361     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00362     {
00363         if ((readerTracker[i].status == READER_ABSENT) &&
00364             (readerTracker[i].fullName != NULL))
00365             HPRemoveHotPluggable(i);
00366     }
00367 
00368     if (AraKiriHotPlug)
00369     {
00370         int retval;
00371 
00372         for (i=0; i<driverSize; i++)
00373         {
00374             /* free strings allocated by strdup() */
00375             free(driverTracker[i].bundleName);
00376             free(driverTracker[i].libraryPath);
00377             free(driverTracker[i].readerName);
00378         }
00379         free(driverTracker);
00380 
00381         Log1(PCSC_LOG_INFO, "Hotplug stopped");
00382         pthread_exit(&retval);
00383     }
00384 
00385     /* free the libusb allocated list & devices */
00386     libusb_free_device_list(devs, 1);
00387 }
00388 
00389 static void HPEstablishUSBNotifications(int pipefd[2])
00390 {
00391     int i, do_polling;
00392     char c = 42;    /* magic value */
00393 
00394     libusb_init(ctx);
00395 
00396     /* scan the USB bus for devices at startup */
00397     HPRescanUsbBus();
00398 
00399     /* signal that the initially connected readers are now visible */
00400     write(pipefd[1], &c, 1);
00401     close(pipefd[1]);
00402 
00403     /* if at least one driver do not have IFD_GENERATE_HOTPLUG */
00404     do_polling = FALSE;
00405     for (i=0; i<driverSize; i++)
00406         if (driverTracker[i].libraryPath)
00407             if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0)
00408             {
00409                 Log2(PCSC_LOG_INFO,
00410                     "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.",
00411                     driverTracker[i].bundleName);
00412                 if (HPForceReaderPolling < 1)
00413                     HPForceReaderPolling = 1;
00414                 break;
00415             }
00416 
00417     if (HPForceReaderPolling)
00418     {
00419         Log2(PCSC_LOG_INFO,
00420                 "Polling forced every %d second(s)", HPForceReaderPolling);
00421         do_polling = TRUE;
00422     }
00423 
00424     if (do_polling)
00425     {
00426         while (!AraKiriHotPlug)
00427         {
00428             SYS_Sleep(HPForceReaderPolling);
00429             HPRescanUsbBus();
00430         }
00431     }
00432     else
00433     {
00434         char dummy;
00435 
00436         pipe(rescan_pipe);
00437         while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0)
00438         {
00439             Log1(PCSC_LOG_INFO, "Reload serial configuration");
00440             HPRescanUsbBus();
00441 #ifdef USE_SERIAL
00442             RFReCheckReaderConf();
00443 #endif
00444             Log1(PCSC_LOG_INFO, "End reload serial configuration");
00445         }
00446         close(rescan_pipe[0]);
00447         rescan_pipe[0] = -1;
00448     }
00449 }
00450 
00451 LONG HPSearchHotPluggables(void)
00452 {
00453     int i;
00454 
00455     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00456     {
00457         readerTracker[i].status = READER_ABSENT;
00458         readerTracker[i].bus_device[0] = '\0';
00459         readerTracker[i].fullName = NULL;
00460     }
00461 
00462     if (HPReadBundleValues())
00463     {
00464         int pipefd[2];
00465         char c;
00466 
00467         if (pipe(pipefd) == -1)
00468         {
00469             Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
00470             return -1;
00471         }
00472 
00473         ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
00474             (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd);
00475 
00476         /* Wait for initial readers to setup */
00477         read(pipefd[0], &c, 1);
00478         close(pipefd[0]);
00479     }
00480 
00481     return 0;
00482 }
00483 
00484 LONG HPStopHotPluggables(void)
00485 {
00486     AraKiriHotPlug = TRUE;
00487     if (rescan_pipe[1] >= 0)
00488     {
00489         close(rescan_pipe[1]);
00490         rescan_pipe[1] = -1;
00491     }
00492 
00493     return 0;
00494 }
00495 
00496 static LONG HPAddHotPluggable(struct libusb_device *dev,
00497     struct libusb_device_descriptor desc,
00498     const char bus_device[], int interface,
00499     struct _driverTracker *driver)
00500 {
00501     int i;
00502     char deviceName[MAX_DEVICENAME];
00503 
00504     Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
00505 
00506     if (interface >= 0)
00507         snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libhal:/org/freedesktop/Hal/devices/usb_device_%04x_%04x_serialnotneeded_if%d",
00508              desc.idVendor, desc.idProduct, desc.idVendor, desc.idProduct,
00509              interface);
00510     else
00511         snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb-1.0:%s",
00512             desc.idVendor, desc.idProduct, bus_device);
00513 
00514     deviceName[sizeof(deviceName) -1] = '\0';
00515 
00516     pthread_mutex_lock(&usbNotifierMutex);
00517 
00518     /* find a free entry */
00519     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00520     {
00521         if (readerTracker[i].fullName == NULL)
00522             break;
00523     }
00524 
00525     if (i==PCSCLITE_MAX_READERS_CONTEXTS)
00526     {
00527         Log2(PCSC_LOG_ERROR,
00528             "Not enough reader entries. Already found %d readers", i);
00529         pthread_mutex_unlock(&usbNotifierMutex);
00530         return 0;
00531     }
00532 
00533     strncpy(readerTracker[i].bus_device, bus_device,
00534         sizeof(readerTracker[i].bus_device));
00535     readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0';
00536 
00537 #ifdef ADD_SERIAL_NUMBER
00538     if (desc.iSerialNumber)
00539     {
00540         libusb_device_handle *device;
00541         unsigned char serialNumber[MAX_READERNAME];
00542         char fullname[MAX_READERNAME];
00543         int ret;
00544 
00545         ret = libusb_open(dev, &device);
00546         if (ret < 0)
00547         {
00548             Log2(PCSC_LOG_ERROR, "libusb_open failed: %d", ret);
00549         }
00550         else
00551         {
00552             ret = libusb_get_string_descriptor_ascii(device, desc.iSerialNumber,
00553                 serialNumber, MAX_READERNAME);
00554             libusb_close(device);
00555 
00556             if (ret < 0)
00557             {
00558                 Log2(PCSC_LOG_ERROR,
00559                     "libusb_get_string_descriptor_ascii failed: %d", ret);
00560                 readerTracker[i].fullName = strdup(driver->readerName);
00561             }
00562             else
00563             {
00564                 snprintf(fullname, sizeof(fullname), "%s (%s)",
00565                     driver->readerName, serialNumber);
00566                 readerTracker[i].fullName = strdup(fullname);
00567             }
00568         }
00569     }
00570     else
00571 #endif
00572         readerTracker[i].fullName = strdup(driver->readerName);
00573 
00574     if (RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
00575         driver->libraryPath, deviceName) == SCARD_S_SUCCESS)
00576         readerTracker[i].status = READER_PRESENT;
00577     else
00578     {
00579         readerTracker[i].status = READER_FAILED;
00580 
00581         (void)CheckForOpenCT();
00582     }
00583 
00584     pthread_mutex_unlock(&usbNotifierMutex);
00585 
00586     return 1;
00587 }   /* End of function */
00588 
00589 static LONG HPRemoveHotPluggable(int reader_index)
00590 {
00591     pthread_mutex_lock(&usbNotifierMutex);
00592 
00593     Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index,
00594         readerTracker[reader_index].bus_device);
00595 
00596     RFRemoveReader(readerTracker[reader_index].fullName,
00597         PCSCLITE_HP_BASE_PORT + reader_index);
00598     free(readerTracker[reader_index].fullName);
00599     readerTracker[reader_index].status = READER_ABSENT;
00600     readerTracker[reader_index].bus_device[0] = '\0';
00601     readerTracker[reader_index].fullName = NULL;
00602 
00603     pthread_mutex_unlock(&usbNotifierMutex);
00604 
00605     return 1;
00606 }   /* End of function */
00607 
00611 ULONG HPRegisterForHotplugEvents(void)
00612 {
00613     (void)pthread_mutex_init(&usbNotifierMutex, NULL);
00614     return 0;
00615 }
00616 
00617 void HPReCheckSerialReaders(void)
00618 {
00619     if (rescan_pipe[1] >= 0)
00620     {
00621         char dummy = 0;
00622         write(rescan_pipe[1], &dummy, sizeof(dummy));
00623     }
00624 }
00625 
00626 #endif
00627