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

Generated on Mon Aug 17 01:00:09 2009 for pcsc-lite by  doxygen 1.5.9