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

Generated on Sat Oct 14 22:17:34 2006 for pcsc-lite by  doxygen 1.4.7