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

Generated on Wed Oct 8 02:23:54 2008 for pcsc-lite by  doxygen 1.5.6