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 5114 2010-08-05 08:02:09Z 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-1.0/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", bus_number, device_address */
00051 #define BUS_DEVICE_STRSIZE  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     long manuID;
00080     long 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[], struct _driverTracker *driver);
00102 static LONG HPRemoveHotPluggable(int reader_index);
00103 
00104 static LONG HPReadBundleValues(void)
00105 {
00106     LONG rv;
00107     DIR *hpDir;
00108     struct dirent *currFP = NULL;
00109     char fullPath[FILENAME_MAX];
00110     char fullLibPath[FILENAME_MAX];
00111     char keyValue[TOKEN_MAX_VALUE_SIZE];
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     while ((currFP = readdir(hpDir)) != 0)
00133     {
00134         if (strstr(currFP->d_name, ".bundle") != 0)
00135         {
00136             int alias = 0;
00137 
00138             /*
00139              * The bundle exists - let's form a full path name and get the
00140              * vendor and product ID's for this particular bundle
00141              */
00142             snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
00143                 PCSCLITE_HP_DROPDIR, currFP->d_name);
00144             fullPath[sizeof(fullPath) - 1] = '\0';
00145 
00146             /* while we find a nth ifdVendorID in Info.plist */
00147             while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
00148                 keyValue, alias) == 0)
00149             {
00150                 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00151 
00152                 /* Get ifdVendorID */
00153                 rv = LTPBundleFindValueWithKey(fullPath,
00154                     PCSCLITE_HP_MANUKEY_NAME, keyValue, alias);
00155                 if (rv == 0)
00156                     driverTracker[listCount].manuID = strtol(keyValue, NULL, 16);
00157 
00158                 /* get ifdProductID */
00159                 rv = LTPBundleFindValueWithKey(fullPath,
00160                     PCSCLITE_HP_PRODKEY_NAME, keyValue, alias);
00161                 if (rv == 0)
00162                     driverTracker[listCount].productID =
00163                         strtol(keyValue, NULL, 16);
00164 
00165                 /* get ifdFriendlyName */
00166                 rv = LTPBundleFindValueWithKey(fullPath,
00167                     PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias);
00168                 if (rv == 0)
00169                     driverTracker[listCount].readerName = strdup(keyValue);
00170 
00171                 /* get CFBundleExecutable */
00172                 rv = LTPBundleFindValueWithKey(fullPath,
00173                     PCSCLITE_HP_LIBRKEY_NAME, keyValue, 0);
00174                 if (rv == 0)
00175                 {
00176                     snprintf(fullLibPath, sizeof(fullLibPath),
00177                         "%s/%s/Contents/%s/%s",
00178                         PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
00179                         keyValue);
00180                     fullLibPath[sizeof(fullLibPath) - 1] = '\0';
00181                     driverTracker[listCount].libraryPath = strdup(fullLibPath);
00182                 }
00183 
00184                 /* Get ifdCapabilities */
00185                 rv = LTPBundleFindValueWithKey(fullPath,
00186                     PCSCLITE_HP_CPCTKEY_NAME, keyValue, 0);
00187                 if (rv == 0)
00188                     driverTracker[listCount].ifdCapabilities = strtol(keyValue,
00189                         NULL, 16);
00190 
00191 #ifdef DEBUG_HOTPLUG
00192                 Log2(PCSC_LOG_INFO, "Found driver for: %s",
00193                     driverTracker[listCount].readerName);
00194 #endif
00195                 alias++;
00196 
00197                 if (NULL == driverTracker[listCount].readerName)
00198                     continue;
00199 
00200                 listCount++;
00201                 if (listCount >= driverSize)
00202                 {
00203                     int i;
00204 
00205                     /* increase the array size */
00206                     driverSize += DRIVER_TRACKER_SIZE_STEP;
00207 #ifdef DEBUG_HOTPLUG
00208                     Log2(PCSC_LOG_INFO,
00209                         "Increase driverTracker to %d entries", driverSize);
00210 #endif
00211                     driverTracker = realloc(driverTracker,
00212                         driverSize * sizeof(*driverTracker));
00213                     if (NULL == driverTracker)
00214                     {
00215                         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00216                         driverSize = -1;
00217                         return -1;
00218                     }
00219 
00220                     /* clean the newly allocated entries */
00221                     for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
00222                     {
00223                         driverTracker[i].manuID = 0;
00224                         driverTracker[i].productID = 0;
00225                         driverTracker[i].bundleName = NULL;
00226                         driverTracker[i].libraryPath = NULL;
00227                         driverTracker[i].readerName = NULL;
00228                         driverTracker[i].ifdCapabilities = 0;
00229                     }
00230                 }
00231             }
00232         }
00233     }
00234 
00235     driverSize = listCount;
00236     closedir(hpDir);
00237 
00238     rv = TRUE;
00239     if (driverSize == 0)
00240     {
00241         Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
00242         Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
00243         rv = FALSE;
00244     }
00245 #ifdef DEBUG_HOTPLUG
00246     else
00247         Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
00248 #endif
00249 
00250     return rv;
00251 }
00252 
00253 static void HPRescanUsbBus(void)
00254 {
00255     int i, j;
00256     char bus_device[BUS_DEVICE_STRSIZE];
00257     libusb_device **devs, *dev;
00258     ssize_t cnt;
00259 
00260     for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00261         /* clear rollcall */
00262         readerTracker[i].status = READER_ABSENT;
00263 
00264     cnt = libusb_get_device_list(ctx, &devs);
00265     if (cnt < 0)
00266     {
00267         Log1(PCSC_LOG_CRITICAL, "libusb_get_device_list() failed\n");
00268         return;
00269     }
00270 
00271     /* For each USB device */
00272     cnt = 0;
00273     while ((dev = devs[cnt++]) != NULL)
00274     {
00275         struct libusb_device_descriptor desc;
00276         uint8_t bus_number = libusb_get_bus_number(dev);
00277         uint8_t device_address = libusb_get_device_address(dev);
00278 
00279         int r = libusb_get_device_descriptor(dev, &desc);
00280         if (r < 0)
00281         {
00282             Log3(PCSC_LOG_ERROR, "failed to get device descriptor for %d/%d",
00283                 bus_number, device_address);
00284             continue;
00285         }
00286 
00287         /* check if the device is supported by one driver */
00288         for (i=0; i<driverSize; i++)
00289         {
00290             if (driverTracker[i].libraryPath != NULL &&
00291                 desc.idVendor == driverTracker[i].manuID &&
00292                 desc.idProduct == driverTracker[i].productID)
00293             {
00294                 int newreader;
00295 
00296                 /* A known device has been found */
00297                 snprintf(bus_device, BUS_DEVICE_STRSIZE, "%d:%d",
00298                     bus_number, device_address);
00299                 bus_device[BUS_DEVICE_STRSIZE - 1] = '\0';
00300 #ifdef DEBUG_HOTPLUG
00301                 Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s",
00302                     bus_device);
00303 #endif
00304                 newreader = TRUE;
00305 
00306                 /* Check if the reader is a new one */
00307                 for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
00308                 {
00309                     if (strncmp(readerTracker[j].bus_device,
00310                         bus_device, BUS_DEVICE_STRSIZE) == 0)
00311                     {
00312                         /* The reader is already known */
00313                         readerTracker[j].status = READER_PRESENT;
00314                         newreader = FALSE;
00315 #ifdef DEBUG_HOTPLUG
00316                         Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s",
00317                             bus_device);
00318 #endif
00319                         break;
00320                     }
00321                 }
00322 
00323                 /* New reader found */
00324                 if (newreader)
00325                     HPAddHotPluggable(dev, desc, bus_device, &driverTracker[i]);
00326             }
00327         }
00328     }
00329 
00330     /*
00331      * check if all the previously found readers are still present
00332      */
00333     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00334     {
00335         if ((readerTracker[i].status == READER_ABSENT) &&
00336             (readerTracker[i].fullName != NULL))
00337             HPRemoveHotPluggable(i);
00338     }
00339 
00340     if (AraKiriHotPlug)
00341     {
00342         int retval;
00343 
00344         for (i=0; i<driverSize; i++)
00345         {
00346             /* free strings allocated by strdup() */
00347             free(driverTracker[i].bundleName);
00348             free(driverTracker[i].libraryPath);
00349             free(driverTracker[i].readerName);
00350         }
00351         free(driverTracker);
00352 
00353         Log1(PCSC_LOG_INFO, "Hotplug stopped");
00354         pthread_exit(&retval);
00355     }
00356 
00357     /* free the libusb allocated list & devices */
00358     libusb_free_device_list(devs, 1);
00359 }
00360 
00361 static void HPEstablishUSBNotifications(int pipefd[2])
00362 {
00363     int i, do_polling;
00364     char c = 42;    /* magic value */
00365 
00366     libusb_init(ctx);
00367 
00368     /* scan the USB bus for devices at startup */
00369     HPRescanUsbBus();
00370 
00371     /* signal that the initially connected readers are now visible */
00372     write(pipefd[1], &c, 1);
00373     close(pipefd[1]);
00374 
00375     /* if at least one driver do not have IFD_GENERATE_HOTPLUG */
00376     do_polling = FALSE;
00377     for (i=0; i<driverSize; i++)
00378         if (driverTracker[i].libraryPath)
00379             if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0)
00380             {
00381                 Log2(PCSC_LOG_INFO,
00382                     "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.",
00383                     driverTracker[i].bundleName);
00384                 if (HPForceReaderPolling < 1)
00385                     HPForceReaderPolling = 1;
00386                 break;
00387             }
00388 
00389     if (HPForceReaderPolling)
00390     {
00391         Log2(PCSC_LOG_INFO,
00392                 "Polling forced every %d second(s)", HPForceReaderPolling);
00393         do_polling = TRUE;
00394     }
00395 
00396     if (do_polling)
00397     {
00398         while (!AraKiriHotPlug)
00399         {
00400             SYS_Sleep(HPForceReaderPolling);
00401             HPRescanUsbBus();
00402         }
00403     }
00404     else
00405     {
00406         char dummy;
00407 
00408         pipe(rescan_pipe);
00409         while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0)
00410         {
00411             Log1(PCSC_LOG_INFO, "Reload serial configuration");
00412             HPRescanUsbBus();
00413 #ifdef USE_SERIAL
00414             RFReCheckReaderConf();
00415 #endif
00416             Log1(PCSC_LOG_INFO, "End reload serial configuration");
00417         }
00418         close(rescan_pipe[0]);
00419         rescan_pipe[0] = -1;
00420     }
00421 }
00422 
00423 LONG HPSearchHotPluggables(void)
00424 {
00425     int i;
00426     int pipefd[2];
00427     char c;
00428 
00429     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00430     {
00431         readerTracker[i].status = READER_ABSENT;
00432         readerTracker[i].bus_device[0] = '\0';
00433         readerTracker[i].fullName = NULL;
00434     }
00435 
00436     if (pipe(pipefd) == -1)
00437     {
00438         Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
00439         return -1;
00440     }
00441 
00442     if (HPReadBundleValues())
00443         ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
00444             (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd);
00445 
00446     /* Wait for initial readers to setup */
00447     read(pipefd[0], &c, 1);
00448     close(pipefd[0]);
00449 
00450     return 0;
00451 }
00452 
00453 LONG HPStopHotPluggables(void)
00454 {
00455     AraKiriHotPlug = TRUE;
00456     if (rescan_pipe[1] >= 0)
00457     {
00458         close(rescan_pipe[1]);
00459         rescan_pipe[1] = -1;
00460     }
00461 
00462     return 0;
00463 }
00464 
00465 static LONG HPAddHotPluggable(struct libusb_device *dev,
00466     struct libusb_device_descriptor desc,
00467     const char bus_device[], struct _driverTracker *driver)
00468 {
00469     int i;
00470     char deviceName[MAX_DEVICENAME];
00471 
00472     Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
00473 
00474     snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb-1.0:%s",
00475         desc.idVendor, desc.idProduct, bus_device);
00476     deviceName[sizeof(deviceName) -1] = '\0';
00477 
00478     pthread_mutex_lock(&usbNotifierMutex);
00479 
00480     /* find a free entry */
00481     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00482     {
00483         if (readerTracker[i].fullName == NULL)
00484             break;
00485     }
00486 
00487     if (i==PCSCLITE_MAX_READERS_CONTEXTS)
00488     {
00489         Log2(PCSC_LOG_ERROR,
00490             "Not enough reader entries. Already found %d readers", i);
00491         pthread_mutex_unlock(&usbNotifierMutex);
00492         return 0;
00493     }
00494 
00495     strncpy(readerTracker[i].bus_device, bus_device,
00496         sizeof(readerTracker[i].bus_device));
00497     readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0';
00498 
00499 #ifdef ADD_SERIAL_NUMBER
00500     if (desc.iSerialNumber)
00501     {
00502         libusb_device_handle *device;
00503         unsigned char serialNumber[MAX_READERNAME];
00504         char fullname[MAX_READERNAME];
00505         int ret;
00506 
00507         ret = libusb_open(dev, &device);
00508         if (ret < 0)
00509         {
00510             Log2(PCSC_LOG_ERROR, "libusb_open failed: %d", ret);
00511         }
00512         else
00513         {
00514             ret = libusb_get_string_descriptor_ascii(device, desc.iSerialNumber,
00515                 serialNumber, MAX_READERNAME);
00516             libusb_close(device);
00517 
00518             if (ret < 0)
00519             {
00520                 Log2(PCSC_LOG_ERROR,
00521                     "libusb_get_string_descriptor_ascii failed: %d", ret);
00522                 readerTracker[i].fullName = strdup(driver->readerName);
00523             }
00524             else
00525             {
00526                 snprintf(fullname, sizeof(fullname), "%s (%s)",
00527                     driver->readerName, serialNumber);
00528                 readerTracker[i].fullName = strdup(fullname);
00529             }
00530         }
00531     }
00532     else
00533 #endif
00534         readerTracker[i].fullName = strdup(driver->readerName);
00535 
00536     if (RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
00537         driver->libraryPath, deviceName) == SCARD_S_SUCCESS)
00538         readerTracker[i].status = READER_PRESENT;
00539     else
00540     {
00541         readerTracker[i].status = READER_FAILED;
00542 
00543         (void)CheckForOpenCT();
00544     }
00545 
00546     pthread_mutex_unlock(&usbNotifierMutex);
00547 
00548     return 1;
00549 }   /* End of function */
00550 
00551 static LONG HPRemoveHotPluggable(int reader_index)
00552 {
00553     pthread_mutex_lock(&usbNotifierMutex);
00554 
00555     Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index,
00556         readerTracker[reader_index].bus_device);
00557 
00558     RFRemoveReader(readerTracker[reader_index].fullName,
00559         PCSCLITE_HP_BASE_PORT + reader_index);
00560     free(readerTracker[reader_index].fullName);
00561     readerTracker[reader_index].status = READER_ABSENT;
00562     readerTracker[reader_index].bus_device[0] = '\0';
00563     readerTracker[reader_index].fullName = NULL;
00564 
00565     pthread_mutex_unlock(&usbNotifierMutex);
00566 
00567     return 1;
00568 }   /* End of function */
00569 
00573 ULONG HPRegisterForHotplugEvents(void)
00574 {
00575     (void)pthread_mutex_init(&usbNotifierMutex, NULL);
00576     return 0;
00577 }
00578 
00579 void HPReCheckSerialReaders(void)
00580 {
00581     if (rescan_pipe[1] >= 0)
00582     {
00583         char dummy = 0;
00584         write(rescan_pipe[1], &dummy, sizeof(dummy));
00585     }
00586 }
00587 
00588 #endif
00589