799 lines
20 KiB
C
799 lines
20 KiB
C
/*
|
|
* MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
|
|
*
|
|
* Copyright (C) 2001-2004
|
|
* David Corcoran <corcoran@musclecard.com>
|
|
* Copyright (C) 2003-2011
|
|
* Ludovic Rousseau <ludovic.rousseau@free.fr>
|
|
* Copyright (C) 2003
|
|
* Toni Andjelkovic <toni@soth.at>
|
|
* Copyright (C) 2003-2004
|
|
* Damien Sauveron <damien.sauveron@labri.fr>
|
|
*
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
3. The name of the author may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief This provides a search API for hot pluggble devices.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
#define _GNU_SOURCE /* for asprintf(3) */
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <libusb.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
|
|
#include "misc.h"
|
|
#include "wintypes.h"
|
|
#include "pcscd.h"
|
|
#include "debuglog.h"
|
|
#include "parser.h"
|
|
#include "readerfactory.h"
|
|
#include "winscard_msg.h"
|
|
#include "sys_generic.h"
|
|
#include "hotplug.h"
|
|
#include "utils.h"
|
|
|
|
#undef DEBUG_HOTPLUG
|
|
|
|
/* format is "%d:%d:%d", bus_number, device_address, interface */
|
|
#define BUS_DEVICE_STRSIZE 10+1+10+1+10+1
|
|
|
|
#define READER_ABSENT 0
|
|
#define READER_PRESENT 1
|
|
#define READER_FAILED 2
|
|
|
|
#define FALSE 0
|
|
#define TRUE 1
|
|
|
|
extern char Add_Interface_In_Name;
|
|
extern char Add_Serial_In_Name;
|
|
|
|
/* we use the default libusb context */
|
|
#define ctx NULL
|
|
|
|
pthread_mutex_t usbNotifierMutex;
|
|
|
|
static pthread_t usbNotifyThread;
|
|
static int driverSize = -1;
|
|
static char AraKiriHotPlug = FALSE;
|
|
static int rescan_pipe[] = { -1, -1 };
|
|
extern int HPForceReaderPolling;
|
|
|
|
/* values of ifdCapabilities bits */
|
|
#define IFD_GENERATE_HOTPLUG 1
|
|
|
|
/**
|
|
* keep track of drivers in a dynamically allocated array
|
|
*/
|
|
static struct _driverTracker
|
|
{
|
|
unsigned int manuID;
|
|
unsigned int productID;
|
|
|
|
char *bundleName;
|
|
char *libraryPath;
|
|
char *readerName;
|
|
int ifdCapabilities;
|
|
char *CFBundleName;
|
|
} *driverTracker = NULL;
|
|
#define DRIVER_TRACKER_SIZE_STEP 8
|
|
|
|
/**
|
|
* keep track of PCSCLITE_MAX_READERS_CONTEXTS simultaneous readers
|
|
*/
|
|
static struct _readerTracker
|
|
{
|
|
char status;
|
|
char bus_device[BUS_DEVICE_STRSIZE]; /**< device name */
|
|
char *fullName; /**< full reader name (including serial number) */
|
|
} readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
|
|
|
|
static LONG HPAddHotPluggable(struct libusb_device *dev,
|
|
struct libusb_device_descriptor desc,
|
|
const char bus_device[],
|
|
const struct libusb_interface *idesc,
|
|
struct _driverTracker *driver,
|
|
struct _driverTracker *classdriver);
|
|
static LONG HPRemoveHotPluggable(int reader_index);
|
|
|
|
static LONG HPReadBundleValues(void)
|
|
{
|
|
LONG rv;
|
|
DIR *hpDir;
|
|
struct dirent *currFP = NULL;
|
|
char fullPath[FILENAME_MAX];
|
|
char fullLibPath[FILENAME_MAX];
|
|
int listCount = 0;
|
|
|
|
hpDir = opendir(PCSCLITE_HP_DROPDIR);
|
|
|
|
if (hpDir == NULL)
|
|
{
|
|
Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
|
|
Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
|
|
return -1;
|
|
}
|
|
|
|
/* allocate a first array */
|
|
driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
|
|
if (NULL == driverTracker)
|
|
{
|
|
Log1(PCSC_LOG_CRITICAL, "Not enough memory");
|
|
return -1;
|
|
}
|
|
driverSize = DRIVER_TRACKER_SIZE_STEP;
|
|
|
|
#define GET_KEY(key, values) \
|
|
rv = LTPBundleFindValueWithKey(&plist, key, values); \
|
|
if (rv) \
|
|
{ \
|
|
Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
|
|
fullPath); \
|
|
continue; \
|
|
}
|
|
|
|
while ((currFP = readdir(hpDir)) != 0)
|
|
{
|
|
if (strstr(currFP->d_name, ".bundle") != 0)
|
|
{
|
|
unsigned int alias;
|
|
list_t plist, *values;
|
|
list_t *manuIDs, *productIDs, *readerNames;
|
|
char *libraryPath;
|
|
int ifdCapabilities;
|
|
char *CFBundleName;
|
|
|
|
/*
|
|
* The bundle exists - let's form a full path name and get the
|
|
* vendor and product ID's for this particular bundle
|
|
*/
|
|
snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
|
|
PCSCLITE_HP_DROPDIR, currFP->d_name);
|
|
fullPath[sizeof(fullPath) - 1] = '\0';
|
|
|
|
rv = bundleParse(fullPath, &plist);
|
|
if (rv)
|
|
continue;
|
|
|
|
/* get CFBundleExecutable */
|
|
GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
|
|
libraryPath = list_get_at(values, 0);
|
|
(void)snprintf(fullLibPath, sizeof(fullLibPath),
|
|
"%s/%s/Contents/%s/%s",
|
|
PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
|
|
libraryPath);
|
|
fullLibPath[sizeof(fullLibPath) - 1] = '\0';
|
|
|
|
/* Get ifdCapabilities */
|
|
GET_KEY(PCSCLITE_HP_CPCTKEY_NAME, &values)
|
|
ifdCapabilities = strtol(list_get_at(values, 0), NULL, 16);
|
|
|
|
GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
|
|
GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
|
|
GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
|
|
|
|
/* Get CFBundleName */
|
|
rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
|
|
&values);
|
|
if (rv)
|
|
CFBundleName = NULL;
|
|
else
|
|
CFBundleName = strdup(list_get_at(values, 0));
|
|
|
|
/* while we find a nth ifdVendorID in Info.plist */
|
|
for (alias=0; alias<list_size(manuIDs); alias++)
|
|
{
|
|
char *value;
|
|
|
|
/* variables entries */
|
|
value = list_get_at(manuIDs, alias);
|
|
driverTracker[listCount].manuID = strtol(value, NULL, 16);
|
|
|
|
value = list_get_at(productIDs, alias);
|
|
driverTracker[listCount].productID = strtol(value, NULL, 16);
|
|
|
|
driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
|
|
|
|
/* constant entries for a same driver */
|
|
driverTracker[listCount].bundleName = strdup(currFP->d_name);
|
|
driverTracker[listCount].libraryPath = strdup(fullLibPath);
|
|
driverTracker[listCount].ifdCapabilities = ifdCapabilities;
|
|
driverTracker[listCount].CFBundleName = CFBundleName;
|
|
|
|
#ifdef DEBUG_HOTPLUG
|
|
Log2(PCSC_LOG_INFO, "Found driver for: %s",
|
|
driverTracker[listCount].readerName);
|
|
#endif
|
|
listCount++;
|
|
if (listCount >= driverSize)
|
|
{
|
|
int i;
|
|
|
|
/* increase the array size */
|
|
driverSize += DRIVER_TRACKER_SIZE_STEP;
|
|
#ifdef DEBUG_HOTPLUG
|
|
Log2(PCSC_LOG_INFO,
|
|
"Increase driverTracker to %d entries", driverSize);
|
|
#endif
|
|
void* tmp = realloc(driverTracker,
|
|
driverSize * sizeof(*driverTracker));
|
|
if (NULL == tmp)
|
|
{
|
|
free(driverTracker);
|
|
Log1(PCSC_LOG_CRITICAL, "Not enough memory");
|
|
driverSize = -1;
|
|
closedir(hpDir);
|
|
return -1;
|
|
}
|
|
driverTracker = tmp;
|
|
|
|
/* clean the newly allocated entries */
|
|
for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
|
|
{
|
|
driverTracker[i].manuID = 0;
|
|
driverTracker[i].productID = 0;
|
|
driverTracker[i].bundleName = NULL;
|
|
driverTracker[i].libraryPath = NULL;
|
|
driverTracker[i].readerName = NULL;
|
|
driverTracker[i].ifdCapabilities = 0;
|
|
driverTracker[i].CFBundleName = NULL;
|
|
}
|
|
}
|
|
}
|
|
bundleRelease(&plist);
|
|
}
|
|
}
|
|
|
|
driverSize = listCount;
|
|
closedir(hpDir);
|
|
|
|
if (driverSize == 0)
|
|
{
|
|
Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
|
|
Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
|
|
}
|
|
#ifdef DEBUG_HOTPLUG
|
|
else
|
|
Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
|
|
#endif
|
|
|
|
return driverSize;
|
|
}
|
|
|
|
static struct _driverTracker *get_driver(unsigned int idVendor,
|
|
unsigned int idProduct, struct _driverTracker **classdriver)
|
|
{
|
|
int i;
|
|
static struct _driverTracker *driver;
|
|
|
|
#ifdef DEBUG_HOTPLUG
|
|
Log3(PCSC_LOG_DEBUG,
|
|
"Looking for a driver for VID: 0x%04X, PID: 0x%04X",
|
|
idVendor, idProduct);
|
|
#endif
|
|
|
|
*classdriver = NULL;
|
|
driver = NULL;
|
|
/* check if the device is supported by one driver */
|
|
for (i=0; i<driverSize; i++)
|
|
{
|
|
if (driverTracker[i].libraryPath != NULL &&
|
|
idVendor == driverTracker[i].manuID &&
|
|
idProduct == driverTracker[i].productID)
|
|
{
|
|
if ((driverTracker[i].CFBundleName != NULL)
|
|
&& (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
|
|
*classdriver = &driverTracker[i];
|
|
else
|
|
/* it is not a CCID Class driver */
|
|
driver = &driverTracker[i];
|
|
}
|
|
}
|
|
|
|
/* if we found a specific driver */
|
|
if (driver)
|
|
return driver;
|
|
|
|
/* else return the Class driver (if any) */
|
|
return *classdriver;
|
|
}
|
|
|
|
static void HPRescanUsbBus(void)
|
|
{
|
|
int i, j;
|
|
char bus_device[BUS_DEVICE_STRSIZE];
|
|
libusb_device **devs, *dev;
|
|
ssize_t cnt;
|
|
|
|
for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
|
|
/* clear rollcall */
|
|
readerTracker[i].status = READER_ABSENT;
|
|
|
|
cnt = libusb_get_device_list(ctx, &devs);
|
|
if (cnt < 0)
|
|
{
|
|
Log2(PCSC_LOG_CRITICAL, "libusb_get_device_list() failed: %s",
|
|
libusb_error_name(cnt));
|
|
return;
|
|
}
|
|
|
|
/* For each USB device */
|
|
cnt = 0;
|
|
while ((dev = devs[cnt++]) != NULL)
|
|
{
|
|
struct libusb_device_descriptor desc;
|
|
struct libusb_config_descriptor *config_desc;
|
|
uint8_t bus_number = libusb_get_bus_number(dev);
|
|
uint8_t device_address = libusb_get_device_address(dev);
|
|
struct _driverTracker *driver, *classdriver;
|
|
int interface;
|
|
|
|
int r = libusb_get_device_descriptor(dev, &desc);
|
|
if (r < 0)
|
|
{
|
|
Log4(PCSC_LOG_ERROR,
|
|
"failed to get device descriptor for %d/%d: %s",
|
|
bus_number, device_address, libusb_error_name(r));
|
|
continue;
|
|
}
|
|
|
|
r = libusb_get_active_config_descriptor(dev, &config_desc);
|
|
if (r < 0)
|
|
{
|
|
Log4(PCSC_LOG_ERROR, "failed to get device config for %d/%d: %s",
|
|
bus_number, device_address, libusb_error_name(r));
|
|
continue;
|
|
}
|
|
|
|
driver = get_driver(desc.idVendor, desc.idProduct, &classdriver);
|
|
if (NULL == driver)
|
|
{
|
|
/* not a smart card reader */
|
|
#ifdef DEBUG_HOTPLUG
|
|
Log3(PCSC_LOG_DEBUG, "%d/%d is not a supported smart card reader",
|
|
bus_number, device_address);
|
|
#endif
|
|
libusb_free_config_descriptor(config_desc);
|
|
continue;
|
|
}
|
|
|
|
#ifdef DEBUG_HOTPLUG
|
|
Log3(PCSC_LOG_DEBUG, "Found matching USB device: %d:%d",
|
|
bus_number, device_address);
|
|
#endif
|
|
|
|
for (interface = 0; interface < config_desc->bNumInterfaces;
|
|
interface++)
|
|
{
|
|
int newreader;
|
|
|
|
/* A known device has been found */
|
|
snprintf(bus_device, BUS_DEVICE_STRSIZE, "%d:%d:%d",
|
|
bus_number, device_address, interface);
|
|
bus_device[BUS_DEVICE_STRSIZE - 1] = '\0';
|
|
newreader = TRUE;
|
|
|
|
/* Check if the reader is a new one */
|
|
for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
|
|
{
|
|
if (strncmp(readerTracker[j].bus_device,
|
|
bus_device, BUS_DEVICE_STRSIZE) == 0)
|
|
{
|
|
/* The reader is already known */
|
|
readerTracker[j].status = READER_PRESENT;
|
|
newreader = FALSE;
|
|
#ifdef DEBUG_HOTPLUG
|
|
Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s",
|
|
bus_device);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* New reader found */
|
|
if (newreader)
|
|
HPAddHotPluggable(dev, desc, bus_device,
|
|
&config_desc->interface[interface], driver, classdriver);
|
|
}
|
|
|
|
libusb_free_config_descriptor(config_desc);
|
|
}
|
|
|
|
/*
|
|
* check if all the previously found readers are still present
|
|
*/
|
|
for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
|
|
{
|
|
if ((readerTracker[i].status == READER_ABSENT) &&
|
|
(readerTracker[i].fullName != NULL))
|
|
HPRemoveHotPluggable(i);
|
|
}
|
|
|
|
if (AraKiriHotPlug)
|
|
{
|
|
int retval;
|
|
|
|
for (i=0; i<driverSize; i++)
|
|
{
|
|
/* free strings allocated by strdup() */
|
|
free(driverTracker[i].bundleName);
|
|
free(driverTracker[i].libraryPath);
|
|
free(driverTracker[i].readerName);
|
|
free(driverTracker[i].CFBundleName);
|
|
}
|
|
free(driverTracker);
|
|
|
|
Log1(PCSC_LOG_INFO, "Hotplug stopped");
|
|
pthread_exit(&retval);
|
|
}
|
|
|
|
/* free the libusb allocated list & devices */
|
|
libusb_free_device_list(devs, 1);
|
|
}
|
|
|
|
static void * HPEstablishUSBNotifications(int pipefd[2])
|
|
{
|
|
int i, do_polling;
|
|
int r;
|
|
char c = 42; /* magic value */
|
|
|
|
r = libusb_init(ctx);
|
|
if (r < 0)
|
|
{
|
|
Log2(PCSC_LOG_CRITICAL, "libusb_init failed: %s", libusb_error_name(r));
|
|
/* emergency exit */
|
|
kill(getpid(), SIGTERM);
|
|
return NULL;
|
|
}
|
|
|
|
/* scan the USB bus for devices at startup */
|
|
HPRescanUsbBus();
|
|
|
|
/* signal that the initially connected readers are now visible */
|
|
if (write(pipefd[1], &c, 1) == -1)
|
|
{
|
|
Log2(PCSC_LOG_ERROR, "write: %s", strerror(errno));
|
|
return NULL;
|
|
}
|
|
|
|
/* if at least one driver do not have IFD_GENERATE_HOTPLUG */
|
|
do_polling = FALSE;
|
|
for (i=0; i<driverSize; i++)
|
|
if (driverTracker[i].libraryPath)
|
|
if ((driverTracker[i].ifdCapabilities & IFD_GENERATE_HOTPLUG) == 0)
|
|
{
|
|
Log2(PCSC_LOG_INFO,
|
|
"Driver %s does not support IFD_GENERATE_HOTPLUG. Using active polling instead.",
|
|
driverTracker[i].bundleName);
|
|
if (HPForceReaderPolling < 1)
|
|
HPForceReaderPolling = 1;
|
|
break;
|
|
}
|
|
|
|
if (HPForceReaderPolling)
|
|
{
|
|
Log2(PCSC_LOG_INFO,
|
|
"Polling forced every %d second(s)", HPForceReaderPolling);
|
|
do_polling = TRUE;
|
|
}
|
|
|
|
if (do_polling)
|
|
{
|
|
while (!AraKiriHotPlug)
|
|
{
|
|
SYS_Sleep(HPForceReaderPolling);
|
|
HPRescanUsbBus();
|
|
}
|
|
libusb_exit(ctx);
|
|
}
|
|
else
|
|
{
|
|
char dummy;
|
|
|
|
if (pipe(rescan_pipe) == -1)
|
|
{
|
|
Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
|
|
return NULL;
|
|
}
|
|
while (read(rescan_pipe[0], &dummy, sizeof(dummy)) > 0)
|
|
{
|
|
Log1(PCSC_LOG_INFO, "Reload serial configuration");
|
|
HPRescanUsbBus();
|
|
#ifdef USE_SERIAL
|
|
RFReCheckReaderConf();
|
|
#endif
|
|
Log1(PCSC_LOG_INFO, "End reload serial configuration");
|
|
}
|
|
close(rescan_pipe[0]);
|
|
rescan_pipe[0] = -1;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
LONG HPSearchHotPluggables(void)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
|
|
{
|
|
readerTracker[i].status = READER_ABSENT;
|
|
readerTracker[i].bus_device[0] = '\0';
|
|
readerTracker[i].fullName = NULL;
|
|
}
|
|
|
|
if (HPReadBundleValues() > 0)
|
|
{
|
|
int pipefd[2];
|
|
char c;
|
|
|
|
if (pipe(pipefd) == -1)
|
|
{
|
|
Log2(PCSC_LOG_ERROR, "pipe: %s", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
|
|
(PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, pipefd);
|
|
|
|
/* Wait for initial readers to setup */
|
|
if (read(pipefd[0], &c, 1) == -1)
|
|
{
|
|
Log2(PCSC_LOG_ERROR, "read: %s", strerror(errno));
|
|
return -1;
|
|
};
|
|
|
|
/* cleanup pipe fd */
|
|
close(pipefd[0]);
|
|
close(pipefd[1]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LONG HPStopHotPluggables(void)
|
|
{
|
|
AraKiriHotPlug = TRUE;
|
|
if (rescan_pipe[1] >= 0)
|
|
{
|
|
close(rescan_pipe[1]);
|
|
rescan_pipe[1] = -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static LONG HPAddHotPluggable(struct libusb_device *dev,
|
|
struct libusb_device_descriptor desc,
|
|
const char bus_device[],
|
|
const struct libusb_interface *idesc,
|
|
struct _driverTracker *driver,
|
|
struct _driverTracker *classdriver)
|
|
{
|
|
int i;
|
|
uint8_t iInterface = 0;
|
|
uint8_t iSerialNumber = 0;
|
|
char *deviceName;
|
|
|
|
Log2(PCSC_LOG_INFO, "Adding USB device: %s", bus_device);
|
|
|
|
asprintf(&deviceName, "usb:%04x/%04x:libusb-1.0:%s",
|
|
desc.idVendor, desc.idProduct, bus_device);
|
|
|
|
pthread_mutex_lock(&usbNotifierMutex);
|
|
|
|
/* find a free entry */
|
|
for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
|
|
{
|
|
if (readerTracker[i].fullName == NULL)
|
|
break;
|
|
}
|
|
|
|
if (i==PCSCLITE_MAX_READERS_CONTEXTS)
|
|
{
|
|
Log2(PCSC_LOG_ERROR,
|
|
"Not enough reader entries. Already found %d readers", i);
|
|
pthread_mutex_unlock(&usbNotifierMutex);
|
|
return 0;
|
|
}
|
|
|
|
strncpy(readerTracker[i].bus_device, bus_device,
|
|
sizeof(readerTracker[i].bus_device));
|
|
readerTracker[i].bus_device[sizeof(readerTracker[i].bus_device) - 1] = '\0';
|
|
readerTracker[i].fullName = NULL;
|
|
|
|
if (Add_Interface_In_Name && idesc->num_altsetting > 0)
|
|
iInterface = idesc->altsetting[0].iInterface;
|
|
|
|
if (Add_Serial_In_Name)
|
|
iSerialNumber = desc.iSerialNumber;
|
|
|
|
if (iSerialNumber != 0 || iInterface != 0)
|
|
{
|
|
libusb_device_handle *device;
|
|
int ret;
|
|
|
|
ret = libusb_open(dev, &device);
|
|
if (ret < 0)
|
|
{
|
|
Log2(PCSC_LOG_ERROR, "libusb_open failed: %s",
|
|
libusb_error_name(ret));
|
|
}
|
|
else
|
|
{
|
|
unsigned char interfaceName[MAX_READERNAME];
|
|
unsigned char serialNumber[MAX_READERNAME];
|
|
char fullname[MAX_READERNAME * 3];
|
|
fullname[0] = '\0';
|
|
int ret_interface = 0;
|
|
int ret_serial = 0;
|
|
|
|
if (iInterface)
|
|
{
|
|
ret_interface = libusb_get_string_descriptor_ascii(device,
|
|
iInterface, interfaceName, sizeof interfaceName);
|
|
if (ret_interface < 0)
|
|
{
|
|
Log2(PCSC_LOG_ERROR,
|
|
"libusb_get_string_descriptor_ascii failed: %s",
|
|
libusb_error_name(ret_interface));
|
|
}
|
|
}
|
|
|
|
if (iSerialNumber)
|
|
{
|
|
ret_serial = libusb_get_string_descriptor_ascii(device,
|
|
iSerialNumber, serialNumber, sizeof serialNumber);
|
|
if (ret_serial < 0)
|
|
{
|
|
Log2(PCSC_LOG_ERROR,
|
|
"libusb_get_string_descriptor_ascii failed: %s",
|
|
libusb_error_name(ret_serial));
|
|
}
|
|
}
|
|
|
|
libusb_close(device);
|
|
|
|
if (ret_interface > 0 && ret_serial > 0)
|
|
{
|
|
snprintf(fullname, sizeof(fullname), "%s [%s] (%s)",
|
|
driver->readerName, interfaceName, serialNumber);
|
|
}
|
|
else
|
|
{
|
|
if (ret_interface > 0)
|
|
{
|
|
snprintf(fullname, sizeof(fullname), "%s [%s]",
|
|
driver->readerName, interfaceName);
|
|
}
|
|
else
|
|
{
|
|
if (ret_serial > 0)
|
|
{
|
|
snprintf(fullname, sizeof(fullname), "%s (%s)",
|
|
driver->readerName, serialNumber);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fullname[0] != '\0')
|
|
readerTracker[i].fullName = strdup(fullname);
|
|
}
|
|
}
|
|
|
|
if (readerTracker[i].fullName == NULL)
|
|
readerTracker[i].fullName = strdup(driver->readerName);
|
|
|
|
LONG ret;
|
|
ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
|
|
driver->libraryPath, deviceName);
|
|
/* success by default */
|
|
readerTracker[i].status = READER_PRESENT;
|
|
if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
|
|
{
|
|
Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
|
|
driver->readerName);
|
|
|
|
if (classdriver && driver != classdriver)
|
|
{
|
|
/* the reader can also be used by the a class driver */
|
|
ret = RFAddReader(readerTracker[i].fullName,
|
|
PCSCLITE_HP_BASE_PORT + i,
|
|
classdriver->libraryPath, deviceName);
|
|
if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
|
|
{
|
|
Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
|
|
driver->readerName);
|
|
readerTracker[i].status = READER_FAILED;
|
|
}
|
|
}
|
|
else
|
|
readerTracker[i].status = READER_FAILED;
|
|
}
|
|
|
|
if (READER_FAILED == readerTracker[i].status)
|
|
(void)CheckForOpenCT();
|
|
|
|
pthread_mutex_unlock(&usbNotifierMutex);
|
|
|
|
free(deviceName);
|
|
|
|
return 1;
|
|
} /* End of function */
|
|
|
|
static LONG HPRemoveHotPluggable(int reader_index)
|
|
{
|
|
pthread_mutex_lock(&usbNotifierMutex);
|
|
|
|
Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", reader_index,
|
|
readerTracker[reader_index].bus_device);
|
|
|
|
RFRemoveReader(readerTracker[reader_index].fullName,
|
|
PCSCLITE_HP_BASE_PORT + reader_index, REMOVE_READER_FLAG_REMOVED);
|
|
free(readerTracker[reader_index].fullName);
|
|
readerTracker[reader_index].status = READER_ABSENT;
|
|
readerTracker[reader_index].bus_device[0] = '\0';
|
|
readerTracker[reader_index].fullName = NULL;
|
|
|
|
pthread_mutex_unlock(&usbNotifierMutex);
|
|
|
|
return 1;
|
|
} /* End of function */
|
|
|
|
/**
|
|
* Sets up callbacks for device hotplug events.
|
|
*/
|
|
ULONG HPRegisterForHotplugEvents(void)
|
|
{
|
|
(void)pthread_mutex_init(&usbNotifierMutex, NULL);
|
|
return 0;
|
|
}
|
|
|
|
void HPReCheckSerialReaders(void)
|
|
{
|
|
Log0(PCSC_LOG_INFO);
|
|
if (rescan_pipe[1] >= 0)
|
|
{
|
|
char dummy = 0;
|
|
if (write(rescan_pipe[1], &dummy, sizeof(dummy)) == -1)
|
|
Log2(PCSC_LOG_ERROR, "write: %s", strerror(errno));
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|