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

Generated on Fri Sep 15 14:58:51 2006 for pcsc-lite by  doxygen 1.4.7