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

Generated on Mon Aug 17 01:00:09 2009 for pcsc-lite by  doxygen 1.5.9