hotplug_linux.c

Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 2001-2003
00005  *  David Corcoran <corcoran@linuxnet.com>
00006  * Copyright (C) 2002-2009
00007  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00008  *
00009  * The USB code was based partly on Johannes Erdfelt
00010  * libusb code found at libusb.sourceforge.net
00011  *
00012  * $Id: hotplug_linux.c 4905 2010-04-29 09:45:54Z rousseau $
00013  */
00014 
00020 #include "config.h"
00021 #include <string.h>
00022 
00023 #if defined(__linux__) && !defined(HAVE_LIBUSB) && !defined(HAVE_LIBHAL)
00024 #include <sys/types.h>
00025 #include <stdio.h>
00026 #include <dirent.h>
00027 #include <fcntl.h>
00028 #include <time.h>
00029 #include <stdlib.h>
00030 #include <unistd.h>
00031 #include <pthread.h>
00032 
00033 #include "misc.h"
00034 #include "pcsclite.h"
00035 #include "pcscd.h"
00036 #include "debuglog.h"
00037 #include "parser.h"
00038 #include "readerfactory.h"
00039 #include "winscard_msg.h"
00040 #include "sys_generic.h"
00041 #include "hotplug.h"
00042 #include "utils.h"
00043 
00044 #define PCSCLITE_USB_PATH       "/proc/bus/usb"
00045 
00046 #define FALSE           0
00047 #define TRUE            1
00048 
00049 pthread_mutex_t usbNotifierMutex;
00050 
00051 struct usb_device_descriptor
00052 {
00053     u_int8_t bLength;
00054     u_int8_t bDescriptorType;
00055     u_int16_t bcdUSB;
00056     u_int8_t bDeviceClass;
00057     u_int8_t bDeviceSubClass;
00058     u_int8_t bDeviceProtocol;
00059     u_int8_t bMaxPacketSize0;
00060     u_int16_t idVendor;
00061     u_int16_t idProduct;
00062     u_int16_t bcdDevice;
00063     u_int8_t iManufacturer;
00064     u_int8_t iProduct;
00065     u_int8_t iSerialNumber;
00066     u_int8_t bNumConfigurations;
00067 }
00068 __attribute__ ((packed));
00069 
00070 static LONG HPAddHotPluggable(int, unsigned long);
00071 static LONG HPRemoveHotPluggable(int, unsigned long);
00072 static LONG HPReadBundleValues(void);
00073 static void HPEstablishUSBNotifications(void);
00074 
00075 static pthread_t usbNotifyThread;
00076 static int AraKiriHotPlug = FALSE;
00077 static int bundleSize = 0;
00078 
00082 static struct _bundleTracker
00083 {
00084     long  manuID;
00085     long  productID;
00086 
00087     struct _deviceNumber {
00088         int  id;
00089         char status;
00090     } deviceNumber[PCSCLITE_MAX_READERS_CONTEXTS];
00091 
00092     char *bundleName;
00093     char *libraryPath;
00094     char *readerName;
00095 }
00096 bundleTracker[PCSCLITE_MAX_READERS_CONTEXTS];
00097 
00098 static LONG HPReadBundleValues(void)
00099 {
00100 
00101     LONG rv;
00102     DIR *hpDir;
00103     struct dirent *currFP = 0;
00104     char fullPath[FILENAME_MAX];
00105     char fullLibPath[FILENAME_MAX];
00106     char keyValue[TOKEN_MAX_VALUE_SIZE];
00107     int listCount = 0;
00108 
00109     hpDir = opendir(PCSCLITE_HP_DROPDIR);
00110 
00111     if (hpDir == NULL)
00112     {
00113         Log1(PCSC_LOG_INFO,
00114             "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
00115         Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd.");
00116         return -1;
00117     }
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, FILENAME_MAX, "%s/%s/Contents/Info.plist",
00130                 PCSCLITE_HP_DROPDIR, currFP->d_name);
00131             fullPath[FILENAME_MAX - 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                 bundleTracker[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                     bundleTracker[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                     bundleTracker[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                     bundleTracker[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                     bundleTracker[listCount].libraryPath = strdup(fullLibPath);
00168                 }
00169 
00170                 listCount++;
00171                 alias++;
00172 
00173                 if (listCount >= sizeof(bundleTracker)/sizeof(bundleTracker[0]))
00174                 {
00175                     Log2(PCSC_LOG_CRITICAL, "Too many readers declared. Maximum is %d", sizeof(bundleTracker)/sizeof(bundleTracker[0]));
00176                     goto end;
00177                 }
00178             }
00179         }
00180     }
00181 
00182 end:
00183     bundleSize = listCount;
00184 
00185     if (bundleSize == 0)
00186     {
00187         Log1(PCSC_LOG_INFO,
00188             "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
00189         Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
00190     }
00191 
00192     closedir(hpDir);
00193     return 0;
00194 }
00195 
00196 static void HPEstablishUSBNotifications(void)
00197 {
00198 
00199     int i, j, usbDeviceStatus;
00200     DIR *dir, *dirB;
00201     struct dirent *entry, *entryB;
00202     int deviceNumber;
00203     int suspectDeviceNumber;
00204     char dirpath[FILENAME_MAX];
00205     char filename[FILENAME_MAX];
00206     int fd, ret;
00207     struct usb_device_descriptor usbDescriptor;
00208 
00209     usbDeviceStatus = 0;
00210     suspectDeviceNumber = 0;
00211 
00212     while (1)
00213     {
00214         for (i = 0; i < bundleSize; i++)
00215         {
00216             usbDeviceStatus     = 0;
00217             suspectDeviceNumber = 0;
00218 
00219             for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
00220                 /* clear rollcall */
00221                 bundleTracker[i].deviceNumber[j].status = 0;
00222 
00223             dir = NULL;
00224             dir = opendir(PCSCLITE_USB_PATH);
00225             if (dir == NULL)
00226             {
00227                 Log1(PCSC_LOG_ERROR,
00228                     "Cannot open USB path directory: " PCSCLITE_USB_PATH);
00229                 return;
00230             }
00231 
00232             entry = NULL;
00233             while ((entry = readdir(dir)) != 0)
00234             {
00235 
00236                 /*
00237                  * Skip anything starting with a
00238                  */
00239                 if (entry->d_name[0] == '.')
00240                     continue;
00241                 if (!strchr("0123456789",
00242                         entry->d_name[strlen(entry->d_name) - 1]))
00243                 {
00244                     continue;
00245                 }
00246 
00247                 sprintf(dirpath, "%s/%s", PCSCLITE_USB_PATH, entry->d_name);
00248 
00249                 dirB = opendir(dirpath);
00250 
00251                 if (dirB == NULL)
00252                 {
00253                     Log2(PCSC_LOG_ERROR,
00254                         "USB path seems to have disappeared %s", dirpath);
00255                     closedir(dir);
00256                     return;
00257                 }
00258 
00259                 while ((entryB = readdir(dirB)) != NULL)
00260                 {
00261                     /*
00262                      * Skip anything starting with a
00263                      */
00264                     if (entryB->d_name[0] == '.')
00265                         continue;
00266 
00267                     /* Get the device number so we can distinguish
00268                        multiple readers */
00269                     sprintf(filename, "%s/%s", dirpath, entryB->d_name);
00270                     sscanf(entryB->d_name, "%d", &deviceNumber);
00271 
00272                     fd = open(filename, O_RDONLY);
00273                     if (fd < 0)
00274                         continue;
00275 
00276                     ret = read(fd, (void *) &usbDescriptor,
00277                         sizeof(usbDescriptor));
00278 
00279                     close(fd);
00280 
00281                     if (ret < 0)
00282                         continue;
00283 
00284                     /*
00285                      * Device is found and we don't know about it
00286                      */
00287 
00288                     if (usbDescriptor.idVendor == bundleTracker[i].manuID &&
00289                         usbDescriptor.idProduct == bundleTracker[i].productID &&
00290                         usbDescriptor.idVendor !=0 &&
00291                         usbDescriptor.idProduct != 0)
00292                     {
00293                         for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
00294                         {
00295                             if (bundleTracker[i].deviceNumber[j].id == deviceNumber &&
00296                                 bundleTracker[i].deviceNumber[j].id != 0)
00297                             {
00298                                 bundleTracker[i].deviceNumber[j].status = 1; /* i'm here */
00299                                 break;
00300                             }
00301                         }
00302 
00303                         if (j == PCSCLITE_MAX_READERS_CONTEXTS)
00304                         {
00305                             usbDeviceStatus = 1;
00306                             suspectDeviceNumber = deviceNumber;
00307                         }
00308                     }
00309 
00310                 } /* End of while */
00311 
00312                 closedir(dirB);
00313 
00314             } /* End of while */
00315 
00316 
00317             if (usbDeviceStatus == 1)
00318             {
00319                 pthread_mutex_lock(&usbNotifierMutex);
00320 
00321                 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
00322                 {
00323                     if (bundleTracker[i].deviceNumber[j].id == 0)
00324                         break;
00325                 }
00326 
00327                 if (j == PCSCLITE_MAX_READERS_CONTEXTS)
00328                     Log1(PCSC_LOG_ERROR,
00329                         "Too many identical readers plugged in");
00330                 else
00331                 {
00332                     HPAddHotPluggable(i, j+1);
00333                     bundleTracker[i].deviceNumber[j].id = suspectDeviceNumber;
00334                 }
00335 
00336                 pthread_mutex_unlock(&usbNotifierMutex);
00337             }
00338             else
00339                 if (usbDeviceStatus == 0)
00340                 {
00341 
00342                     for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
00343                     {
00344                         if (bundleTracker[i].deviceNumber[j].id != 0 &&
00345                             bundleTracker[i].deviceNumber[j].status == 0)
00346                         {
00347                             pthread_mutex_lock(&usbNotifierMutex);
00348                             HPRemoveHotPluggable(i, j+1);
00349                             bundleTracker[i].deviceNumber[j].id = 0;
00350                             pthread_mutex_unlock(&usbNotifierMutex);
00351                         }
00352                     }
00353                 }
00354                 else
00355                 {
00356                     /*
00357                      * Do nothing - no USB devices found
00358                      */
00359                 }
00360 
00361             if (dir)
00362                 closedir(dir);
00363 
00364         }   /* End of for..loop */
00365 
00366         SYS_Sleep(1);
00367         if (AraKiriHotPlug)
00368         {
00369             int retval;
00370 
00371             Log1(PCSC_LOG_INFO, "Hotplug stopped");
00372             pthread_exit(&retval);
00373         }
00374 
00375     }   /* End of while loop */
00376 }
00377 
00378 LONG HPSearchHotPluggables(void)
00379 {
00380     int i, j;
00381 
00382     for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00383     {
00384         bundleTracker[i].productID  = 0;
00385         bundleTracker[i].manuID     = 0;
00386 
00387         for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
00388             bundleTracker[i].deviceNumber[j].id = 0;
00389     }
00390 
00391     HPReadBundleValues();
00392 
00393     ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
00394         (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, 0);
00395 
00396     return 0;
00397 }
00398 
00399 LONG HPStopHotPluggables(void)
00400 {
00401     AraKiriHotPlug = TRUE;
00402 
00403     return 0;
00404 }
00405 
00406 static LONG HPAddHotPluggable(int i, unsigned long usbAddr)
00407 {
00408     /* NOTE: The deviceName is an empty string "" until someone implements
00409      * the code to get it */
00410     RFAddReader(bundleTracker[i].readerName, PCSCLITE_HP_BASE_PORT + usbAddr,
00411         bundleTracker[i].libraryPath, "");
00412 
00413     return 1;
00414 }   /* End of function */
00415 
00416 static LONG HPRemoveHotPluggable(int i, unsigned long usbAddr)
00417 {
00418     RFRemoveReader(bundleTracker[i].readerName, PCSCLITE_HP_BASE_PORT + usbAddr);
00419 
00420     return 1;
00421 }   /* End of function */
00422 
00426 ULONG HPRegisterForHotplugEvents(void)
00427 {
00428     (void)pthread_mutex_init(&usbNotifierMutex, NULL);
00429     return 0;
00430 }
00431 
00432 void HPReCheckSerialReaders(void)
00433 {
00434 }
00435 
00436 #endif  /* __linux__ && !HAVE_LIBUSB */