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

Generated on Fri Mar 24 04:30:05 2006 for pcsc-lite by  doxygen 1.4.6