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-2009
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 4949 2010-05-17 14:54:47Z 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 <usb.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 #define BUS_DEVICE_STRSIZE  256
00051 
00052 #define READER_ABSENT       0
00053 #define READER_PRESENT      1
00054 #define READER_FAILED       2
00055 
00056 #define FALSE           0
00057 #define TRUE            1
00058 
00059 pthread_mutex_t usbNotifierMutex;
00060 
00061 static pthread_t usbNotifyThread;
00062 static int driverSize = -1;
00063 static char AraKiriHotPlug = FALSE;
00064 static int rescan_pipe[] = { -1, -1 };
00065 extern int HPForceReaderPolling;
00066 
00067 /* values of ifdCapabilities bits */
00068 #define IFD_GENERATE_HOTPLUG 1
00069 
00073 static struct _driverTracker
00074 {
00075     long manuID;
00076     long productID;
00077 
00078     char *bundleName;
00079     char *libraryPath;
00080     char *readerName;
00081     int ifdCapabilities;
00082 } *driverTracker = NULL;
00083 #define DRIVER_TRACKER_SIZE_STEP 8
00084 
00088 static struct _readerTracker
00089 {
00090     char status;
00091     char bus_device[BUS_DEVICE_STRSIZE];    
00092     char *fullName; 
00093 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
00094 
00095 static LONG HPReadBundleValues(void);
00096 static LONG HPAddHotPluggable(struct usb_device *dev, const char bus_device[],
00097     struct _driverTracker *driver);
00098 static LONG HPRemoveHotPluggable(int reader_index);
00099 static void HPRescanUsbBus(void);
00100 static void HPEstablishUSBNotifications(int pipefd[2]);
00101 
00102 static LONG HPReadBundleValues(void)
00103 {
00104     LONG rv;
00105     DIR *hpDir;
00106     struct dirent *currFP = NULL;
00107     char fullPath[FILENAME_MAX];
00108     char fullLibPath[FILENAME_MAX];
00109     char keyValue[TOKEN_MAX_VALUE_SIZE];
00110     int listCount = 0;
00111 
00112     hpDir = opendir(PCSCLITE_HP_DROPDIR);
00113 
00114     if (hpDir == NULL)
00115     {
00116         Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
00117         Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
00118         return -1;
00119     }
00120 
00121     /* allocate a first array */
00122     driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
00123     if (NULL == driverTracker)
00124     {
00125         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00126         return -1;
00127     }
00128     driverSize = DRIVER_TRACKER_SIZE_STEP;
00129 
00130     while ((currFP = readdir(hpDir)) != 0)
00131     {
00132         if (strstr(currFP->d_name, ".bundle") != 0)
00133         {
00134             int alias = 0;
00135 
00136             /*
00137              * The bundle exists - let's form a full path name and get the
00138              * vendor and product ID's for this particular bundle
00139              */
00140             snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
00141                 PCSCLITE_HP_DROPDIR, currFP->d_name);
00142             fullPath[sizeof(fullPath) - 1] = '\0';
00143 
00144             /* while we find a nth ifdVendorID in Info.plist */
00145             while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
00146                 keyValue, alias) == 0)
00147             {
00148                 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00149 
00150                 /* Get ifdVendorID */
00151                 rv = LTPBundleFindValueWithKey(fullPath,
00152                     PCSCLITE_HP_MANUKEY_NAME, keyValue, alias);
00153                 if (rv == 0)
00154                     driverTracker[listCount].manuID = strtol(keyValue, NULL, 16);
00155 
00156                 /* get ifdProductID */
00157                 rv = LTPBundleFindValueWithKey(fullPath,
00158                     PCSCLITE_HP_PRODKEY_NAME, keyValue, alias);
00159                 if (rv == 0)
00160                     driverTracker[listCount].productID =
00161                         strtol(keyValue, NULL, 16);
00162 
00163                 /* get ifdFriendlyName */
00164                 rv = LTPBundleFindValueWithKey(fullPath,
00165                     PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias);
00166                 if (rv == 0)
00167                     driverTracker[listCount].readerName = strdup(keyValue);
00168 
00169                 /* get CFBundleExecutable */
00170                 rv = LTPBundleFindValueWithKey(fullPath,
00171                     PCSCLITE_HP_LIBRKEY_NAME, keyValue, 0);
00172                 if (rv == 0)
00173                 {
00174                     snprintf(fullLibPath, sizeof(fullLibPath),
00175                         "%s/%s/Contents/%s/%s",
00176                         PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
00177                         keyValue);
00178                     fullLibPath[sizeof(fullLibPath) - 1] = '\0';
00179                     driverTracker[listCount].libraryPath = strdup(fullLibPath);
00180                 }
00181 
00182                 /* Get ifdCapabilities */
00183                 rv = LTPBundleFindValueWithKey(fullPath,
00184                     PCSCLITE_HP_CPCTKEY_NAME, keyValue, 0);
00185                 if (rv == 0)
00186                     driverTracker[listCount].ifdCapabilities = strtol(keyValue,
00187                         NULL, 16);
00188 
00189 #ifdef DEBUG_HOTPLUG
00190                 Log2(PCSC_LOG_INFO, "Found driver for: %s",
00191                     driverTracker[listCount].readerName);
00192 #endif
00193                 alias++;
00194 
00195                 if (NULL == driverTracker[listCount].readerName)
00196                     continue;
00197 
00198                 listCount++;
00199                 if (listCount >= driverSize)
00200                 {
00201                     int i;
00202 
00203                     /* increase the array size */
00204                     driverSize += DRIVER_TRACKER_SIZE_STEP;
00205 #ifdef DEBUG_HOTPLUG
00206                     Log2(PCSC_LOG_INFO,
00207                         "Increase driverTracker to %d entries", driverSize);
00208 #endif
00209                     driverTracker = realloc(driverTracker,
00210                         driverSize * sizeof(*driverTracker));
00211                     if (NULL == driverTracker)
00212                     {
00213                         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00214                         driverSize = -1;
00215                         return -1;
00216                     }
00217 
00218                     /* clean the newly allocated entries */
00219                     for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
00220                     {
00221                         driverTracker[i].manuID = 0;
00222                         driverTracker[i].productID = 0;
00223                         driverTracker[i].bundleName = NULL;
00224                         driverTracker[i].libraryPath = NULL;
00225                         driverTracker[i].readerName = NULL;
00226                         driverTracker[i].ifdCapabilities = 0;
00227                     }
00228                 }
00229             }
00230         }
00231     }
00232 
00233     driverSize = listCount;
00234     closedir(hpDir);
00235 
00236     rv = TRUE;
00237     if (driverSize == 0)
00238     {
00239         Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
00240         Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
00241         rv = FALSE;
00242     }
00243 #ifdef DEBUG_HOTPLUG
00244     else
00245         Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
00246 #endif
00247 
00248     return rv;
00249 }
00250 
00251 static void HPRescanUsbBus(void)
00252 {
00253     int i, j;
00254     struct usb_bus *bus;
00255     struct usb_device *dev;
00256     char bus_device[BUS_DEVICE_STRSIZE];
00257 
00258     usb_find_busses();
00259     usb_find_devices();
00260 
00261     for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00262         /* clear rollcall */
00263         readerTracker[i].status = READER_ABSENT;
00264 
00265     /* For each USB bus */
00266     for (bus = usb_get_busses(); bus; bus = bus->next)
00267     {
00268         /* For each USB device */
00269         for (dev = bus->devices; dev; dev = dev->next)
00270         {
00271             /* check if the device is supported by one driver */
00272             for (i=0; i<driverSize; i++)
00273             {
00274                 if (driverTracker[i].libraryPath != NULL &&
00275                     dev->descriptor.idVendor == driverTracker[i].manuID &&
00276                     dev->descriptor.idProduct == driverTracker[i].productID)
00277                 {
00278                     int newreader;
00279 
00280                     /* A known device has been found */
00281                     snprintf(bus_device, BUS_DEVICE_STRSIZE, "%s:%s",
00282                         bus->dirname, dev->filename);
00283                     bus_device[BUS_DEVICE_STRSIZE - 1] = '\0';
00284 #ifdef DEBUG_HOTPLUG
00285                     Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s",
00286                         bus_device);
00287 #endif
00288                     newreader = TRUE;
00289 
00290                     /* Check if the reader is a new one */
00291                     for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
00292                     {
00293                         if (strncmp(readerTracker[j].bus_device,
00294                             bus_device, BUS_DEVICE_STRSIZE) == 0)
00295                         {
00296                             /* The reader is already known */
00297                             readerTracker[j].status = READER_PRESENT;
00298                             newreader = FALSE;
00299 #ifdef DEBUG_HOTPLUG
00300                             Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s",
00301                                 bus_device);
00302 #endif
00303                             break;
00304                         }
00305                     }
00306 
00307                     /* New reader found */
00308                     if (newreader)
00309                         HPAddHotPluggable(dev, bus_device, &driverTracker[i]);
00310                 }
00311             }
00312         } /* End of USB device for..loop */
00313 
00314     } /* End of USB bus for..loop */
00315 
00316     /*
00317      * check if all the previously found readers are still present
00318      */
00319     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00320     {
00321 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
00322         int fd;
00323         char filename[BUS_DEVICE_STRSIZE];
00324 
00325         /*  BSD workaround:
00326          *  ugenopen() in sys/dev/usb/ugen.c returns EBUSY
00327          *  when the character device file is already open.
00328          *  Because of this, open usb devices will not be
00329          *  detected by usb_find_devices(), so we have to
00330          *  check for this explicitly.
00331          */
00332         if (readerTracker[i].status == READER_PRESENT ||
00333             readerTracker[i].fullName == NULL)
00334             continue;
00335 
00336         sscanf(readerTracker[i].bus_device, "%*[^:]%*[:]%s", filename);
00337         fd = open(filename, O_RDONLY);
00338         if (fd == -1)
00339         {
00340             if (errno == EBUSY)
00341             {
00342                 /* The device is present */
00343 #ifdef DEBUG_HOTPLUG
00344                 Log2(PCSC_LOG_DEBUG, "BSD: EBUSY on %s", filename);
00345 #endif
00346                 readerTracker[i].status = READER_PRESENT;
00347             }
00348 #ifdef DEBUG_HOTPLUG
00349             else
00350                 Log3(PCSC_LOG_DEBUG, "BSD: %s error: %s", filename,
00351                     strerror(errno));
00352 #endif
00353         }
00354         else
00355         {
00356 #ifdef DEBUG_HOTPLUG
00357             Log2(PCSC_LOG_DEBUG, "BSD: %s still present", filename);
00358 #endif
00359             readerTracker[i].status = READER_PRESENT;
00360             close(fd);
00361         }
00362 #endif
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 
00386 static void HPEstablishUSBNotifications(int pipefd[2])
00387 {
00388     int i, do_polling;
00389     char c = 42;    /* magic value */
00390 
00391     /* libusb default is /dev/bus/usb but the devices are not yet visible there
00392      * when a hotplug is requested */
00393     setenv("USB_DEVFS_PATH", "/proc/bus/usb", 0);
00394 
00395     usb_init();
00396 
00397     /* scan the USB bus for devices at startup */
00398     HPRescanUsbBus();
00399 
00400     /* signal that the initially connected readers are now visible */
00401     write(pipefd[1], &c, 1);
00402     close(pipefd[1]);
00403 
00404     /* if at least one driver do not have IFD_GENERATE_HOTPLUG */
00405     do_polling = FALSE;
00406     for (i=0; i<driverSize; i++)
00407         if (driverTracker[i].libraryPath)
00408             if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0)
00409             {
00410                 Log2(PCSC_LOG_INFO,
00411                     "Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.",
00412                     driverTracker[i].bundleName);
00413                 if (HPForceReaderPolling < 1)
00414                     HPForceReaderPolling = 1;
00415                 break;
00416             }
00417 
00418     if (HPForceReaderPolling)
00419     {
00420         Log2(PCSC_LOG_INFO,
00421                 "Polling forced every %d second(s)", HPForceReaderPolling);
00422         do_polling = TRUE;
00423     }
00424 
00425     if (do_polling)
00426     {
00427         while (!AraKiriHotPlug)
00428         {
00429             SYS_Sleep(HPForceReaderPolling);
00430             HPRescanUsbBus();
00431         }
00432     }
00433     else
00434     {
00435         char dummy;
00436 
00437         pipe(rescan_pipe);
00438         while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0)
00439         {
00440             Log1(PCSC_LOG_INFO, "Reload serial configuration");
00441             HPRescanUsbBus();
00442 #ifdef USE_SERIAL
00443             RFReCheckReaderConf();
00444 #endif
00445             Log1(PCSC_LOG_INFO, "End reload serial configuration");
00446         }
00447         close(rescan_pipe[0]);
00448         rescan_pipe[0] = -1;
00449     }
00450 }
00451 
00452 LONG HPSearchHotPluggables(void)
00453 {
00454     int i;
00455     int pipefd[2];
00456     char c;
00457 
00458     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00459     {
00460         readerTracker[i].status = READER_ABSENT;
00461         readerTracker[i].bus_device[0] = '\0';
00462         readerTracker[i].fullName = NULL;
00463     }
00464 
00465     if (pipe(pipefd) == -1)
00466     {
00467         Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
00468         return -1;
00469     }
00470 
00471     if (HPReadBundleValues())
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     return 0;
00480 }
00481 
00482 LONG HPStopHotPluggables(void)
00483 {
00484     AraKiriHotPlug = TRUE;
00485     if (rescan_pipe[1] >= 0)
00486     {
00487         close(rescan_pipe[1]);
00488         rescan_pipe[1] = -1;
00489     }
00490 
00491     return 0;
00492 }
00493 
00494 static LONG HPAddHotPluggable(struct usb_device *dev, const char bus_device[],
00495     struct _driverTracker *driver)
00496 {
00497     int i;
00498     char deviceName[MAX_DEVICENAME];
00499 
00500     Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
00501 
00502     snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libusb:%s",
00503         dev->descriptor.idVendor, dev->descriptor.idProduct, bus_device);
00504     deviceName[sizeof(deviceName) -1] = '\0';
00505 
00506     pthread_mutex_lock(&usbNotifierMutex);
00507 
00508     /* find a free entry */
00509     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00510     {
00511         if (readerTracker[i].fullName == NULL)
00512             break;
00513     }
00514 
00515     if (i==PCSCLITE_MAX_READERS_CONTEXTS)
00516     {
00517         Log2(PCSC_LOG_ERROR,
00518             "Not enough reader entries. Already found %d readers", i);
00519         pthread_mutex_unlock(&usbNotifierMutex);
00520         return 0;
00521     }
00522 
00523     strncpy(readerTracker[i].bus_device, bus_device,
00524         sizeof(readerTracker[i].bus_device));
00525     readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0';
00526 
00527 #ifdef ADD_SERIAL_NUMBER
00528     if (dev->descriptor.iSerialNumber)
00529     {
00530         usb_dev_handle *device;
00531         char serialNumber[MAX_READERNAME];
00532         char fullname[MAX_READERNAME];
00533         int ret;
00534 
00535         device = usb_open(dev);
00536         ret = usb_get_string_simple(device, dev->descriptor.iSerialNumber,
00537             serialNumber, MAX_READERNAME);
00538         usb_close(device);
00539 
00540         if (ret < 0)
00541         {
00542             Log2(PCSC_LOG_ERROR, "usb_get_string_simple failed: %s",
00543                 usb_strerror());
00544             readerTracker[i].fullName = strdup(driver->readerName);
00545         }
00546         else
00547         {
00548             snprintf(fullname, sizeof(fullname), "%s (%s)",
00549                 driver->readerName, serialNumber);
00550             readerTracker[i].fullName = strdup(fullname);
00551         }
00552     }
00553     else
00554 #endif
00555         readerTracker[i].fullName = strdup(driver->readerName);
00556 
00557     if (RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
00558         driver->libraryPath, deviceName) == SCARD_S_SUCCESS)
00559         readerTracker[i].status = READER_PRESENT;
00560     else
00561     {
00562         readerTracker[i].status = READER_FAILED;
00563 
00564         (void)CheckForOpenCT();
00565     }
00566 
00567     pthread_mutex_unlock(&usbNotifierMutex);
00568 
00569     return 1;
00570 }   /* End of function */
00571 
00572 static LONG HPRemoveHotPluggable(int reader_index)
00573 {
00574     pthread_mutex_lock(&usbNotifierMutex);
00575 
00576     Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index,
00577         readerTracker[reader_index].bus_device);
00578 
00579     RFRemoveReader(readerTracker[reader_index].fullName,
00580         PCSCLITE_HP_BASE_PORT + reader_index);
00581     free(readerTracker[reader_index].fullName);
00582     readerTracker[reader_index].status = READER_ABSENT;
00583     readerTracker[reader_index].bus_device[0] = '\0';
00584     readerTracker[reader_index].fullName = NULL;
00585 
00586     pthread_mutex_unlock(&usbNotifierMutex);
00587 
00588     return 1;
00589 }   /* End of function */
00590 
00594 ULONG HPRegisterForHotplugEvents(void)
00595 {
00596     (void)pthread_mutex_init(&usbNotifierMutex, NULL);
00597     return 0;
00598 }
00599 
00600 void HPReCheckSerialReaders(void)
00601 {
00602     if (rescan_pipe[1] >= 0)
00603     {
00604         char dummy = 0;
00605         write(rescan_pipe[1], &dummy, sizeof(dummy));
00606     }
00607 }
00608 
00609 #endif
00610