Blame src/ccid_usb.c

Packit Service aee942
/*
Packit Service aee942
	ccid_usb.c: USB access routines using the libusb library
Packit Service aee942
	Copyright (C) 2003-2010	Ludovic Rousseau
Packit Service aee942
Packit Service aee942
	This library is free software; you can redistribute it and/or
Packit Service aee942
	modify it under the terms of the GNU Lesser General Public
Packit Service aee942
	License as published by the Free Software Foundation; either
Packit Service aee942
	version 2.1 of the License, or (at your option) any later version.
Packit Service aee942
Packit Service aee942
	This library is distributed in the hope that it will be useful,
Packit Service aee942
	but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service aee942
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service aee942
	Lesser General Public License for more details.
Packit Service aee942
Packit Service aee942
	You should have received a copy of the GNU Lesser General Public License
Packit Service aee942
	along with this library; if not, write to the Free Software Foundation,
Packit Service aee942
	Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service aee942
*/
Packit Service aee942
Packit Service aee942
#define __CCID_USB__
Packit Service aee942
Packit Service aee942
#include <stdio.h>
Packit Service aee942
#include <string.h>
Packit Service aee942
# ifdef S_SPLINT_S
Packit Service aee942
# include <sys/types.h>
Packit Service aee942
# endif
Packit Service aee942
#include <libusb.h>
Packit Service aee942
#include <stdlib.h>
Packit Service aee942
#include <pthread.h>
Packit Service aee942
#include <sys/time.h>
Packit Service aee942
#include <ifdhandler.h>
Packit Service aee942
Packit Service aee942
#include <config.h>
Packit Service aee942
#include "misc.h"
Packit Service aee942
#include "ccid.h"
Packit Service aee942
#include "debug.h"
Packit Service aee942
#include "defs.h"
Packit Service aee942
#include "utils.h"
Packit Service aee942
#include "parser.h"
Packit Service aee942
#include "ccid_ifdhandler.h"
Packit Service aee942
Packit Service aee942
Packit Service aee942
/* write timeout
Packit Service aee942
 * we don't have to wait a long time since the card was doing nothing */
Packit Service aee942
#define USB_WRITE_TIMEOUT (5 * 1000)	/* 5 seconds timeout */
Packit Service aee942
Packit Service aee942
/*
Packit Service aee942
 * Proprietary USB Class (0xFF) are (or are not) accepted
Packit Service aee942
 * A proprietary class is used for devices released before the final CCID
Packit Service aee942
 * specifications were ready.
Packit Service aee942
 * We should not have problems with non CCID devices because the
Packit Service aee942
 * Manufacturer and Product ID are also used to identify the device */
Packit Service aee942
#define ALLOW_PROPRIETARY_CLASS
Packit Service aee942
Packit Service aee942
#define BUS_DEVICE_STRSIZE 32
Packit Service aee942
Packit Service aee942
/* Using the default libusb context */
Packit Service aee942
/* does not work for libusb <= 1.0.8 */
Packit Service aee942
/* #define ctx NULL */
Packit Service aee942
libusb_context *ctx = NULL;
Packit Service aee942
Packit Service aee942
#define CCID_INTERRUPT_SIZE 8
Packit Service aee942
Packit Service aee942
struct usbDevice_MultiSlot_Extension
Packit Service aee942
{
Packit Service aee942
	int reader_index;
Packit Service aee942
Packit Service aee942
	/* The multi-threaded polling part */
Packit Service aee942
	int terminated;
Packit Service aee942
	int status;
Packit Service aee942
	unsigned char buffer[CCID_INTERRUPT_SIZE];
Packit Service aee942
	pthread_t thread_proc;
Packit Service aee942
	pthread_mutex_t mutex;
Packit Service aee942
	pthread_cond_t condition;
Packit Service aee942
	struct libusb_transfer *transfer;
Packit Service aee942
};
Packit Service aee942
Packit Service aee942
typedef struct
Packit Service aee942
{
Packit Service aee942
	libusb_device_handle *dev_handle;
Packit Service aee942
	uint8_t bus_number;
Packit Service aee942
	uint8_t device_address;
Packit Service aee942
	int interface;
Packit Service aee942
Packit Service aee942
	/*
Packit Service aee942
	 * Endpoints
Packit Service aee942
	 */
Packit Service aee942
	int bulk_in;
Packit Service aee942
	int bulk_out;
Packit Service aee942
	int interrupt;
Packit Service aee942
Packit Service aee942
	/* Number of slots using the same device */
Packit Service aee942
	int real_nb_opened_slots;
Packit Service aee942
	int *nb_opened_slots;
Packit Service aee942
Packit Service aee942
	/*
Packit Service aee942
	 * CCID infos common to USB and serial
Packit Service aee942
	 */
Packit Service aee942
	_ccid_descriptor ccid;
Packit Service aee942
Packit Service aee942
	/* libusb transfer for the polling (or NULL) */
Packit Service aee942
	struct libusb_transfer *polling_transfer;
Packit Service aee942
Packit Service aee942
	/* pointer to the multislot extension (if any) */
Packit Service aee942
	struct usbDevice_MultiSlot_Extension *multislot_extension;
Packit Service aee942
Packit Service aee942
} _usbDevice;
Packit Service aee942
Packit Service aee942
/* The _usbDevice structure must be defined before including ccid_usb.h */
Packit Service aee942
#include "ccid_usb.h"
Packit Service aee942
Packit Service aee942
/* Specific hooks for multislot readers */
Packit Service aee942
static int Multi_InterruptRead(int reader_index, int timeout /* in ms */);
Packit Service aee942
static void Multi_InterruptStop(int reader_index);
Packit Service aee942
static struct usbDevice_MultiSlot_Extension *Multi_CreateFirstSlot(int reader_index);
Packit Service aee942
static struct usbDevice_MultiSlot_Extension *Multi_CreateNextSlot(int physical_reader_index);
Packit Service aee942
static void Multi_PollingTerminate(struct usbDevice_MultiSlot_Extension *msExt);
Packit Service aee942
Packit Service aee942
static int get_end_points(struct libusb_config_descriptor *desc,
Packit Service aee942
	_usbDevice *usbdevice, int num);
Packit Service aee942
int ccid_check_firmware(struct libusb_device_descriptor *desc);
Packit Service aee942
static unsigned int *get_data_rates(unsigned int reader_index,
Packit Service aee942
	struct libusb_config_descriptor *desc, int num);
Packit Service aee942
Packit Service aee942
/* ne need to initialize to 0 since it is static */
Packit Service aee942
static _usbDevice usbDevice[CCID_DRIVER_MAX_READERS];
Packit Service aee942
Packit Service aee942
#define PCSCLITE_MANUKEY_NAME "ifdVendorID"
Packit Service aee942
#define PCSCLITE_PRODKEY_NAME "ifdProductID"
Packit Service aee942
#define PCSCLITE_NAMEKEY_NAME "ifdFriendlyName"
Packit Service aee942
Packit Service aee942
struct _bogus_firmware
Packit Service aee942
{
Packit Service aee942
	int vendor;		/* idVendor */
Packit Service aee942
	int product;	/* idProduct */
Packit Service aee942
	int firmware;	/* bcdDevice: previous firmwares have bugs */
Packit Service aee942
};
Packit Service aee942
Packit Service aee942
static struct _bogus_firmware Bogus_firmwares[] = {
Packit Service aee942
	{ 0x04e6, 0xe001, 0x0516 },	/* SCR 331 */
Packit Service aee942
	{ 0x04e6, 0x5111, 0x0620 },	/* SCR 331-DI */
Packit Service aee942
	{ 0x04e6, 0xe003, 0x0510 },	/* SPR 532 */
Packit Service aee942
	{ 0x0D46, 0x3001, 0x0037 },	/* KAAN Base */
Packit Service aee942
	{ 0x0D46, 0x3002, 0x0037 },	/* KAAN Advanced */
Packit Service aee942
	{ 0x09C3, 0x0008, 0x0203 },	/* ActivCard V2 */
Packit Service aee942
	{ 0x0DC3, 0x1004, 0x0502 },	/* ASE IIIe USBv2 */
Packit Service aee942
	{ 0x0DC3, 0x1102, 0x0607 },	/* ASE IIIe KB USB */
Packit Service aee942
	{ 0x058F, 0x9520, 0x0102 },	/* Alcor AU9520-G */
Packit Service aee942
	{ 0x072F, 0x2200, 0x0206 }, /* ACS ACR122U-WB-R */
Packit Service aee942
	{ 0x08C3, 0x0402, 0x5000 },	/* Precise Biometrics Precise 200 MC */
Packit Service aee942
	{ 0x08C3, 0x0401, 0x5000 },	/* Precise Biometrics Precise 250 MC */
Packit Service aee942
	{ 0x0B0C, 0x0050, 0x0101 },	/* Todos Argos Mini II */
Packit Service aee942
	{ 0x0DC3, 0x0900, 0x0200 }, /* Athena IDProtect Key v2 */
Packit Service aee942
	{ 0x03F0, 0x0036, 0x0124 }, /* HP USB CCID Smartcard Keyboard */
Packit Service aee942
	{ 0x062D, 0x0001, 0x0102 }, /* THRC Smart Card Reader */
Packit Service aee942
	{ 0x04E6, 0x5291, 0x0112 }, /* SCM SCL010 Contactless Reader */
Packit Service aee942
Packit Service aee942
	/* the firmware version is not correct since I do not have received a
Packit Service aee942
	 * working reader yet */
Packit Service aee942
#ifndef O2MICRO_OZ776_PATCH
Packit Service aee942
	{ 0x0b97, 0x7762, 0x0111 },	/* Oz776S */
Packit Service aee942
#endif
Packit Service aee942
};
Packit Service aee942
Packit Service aee942
/* data rates supported by the secondary slots on the GemCore Pos Pro & SIM Pro */
Packit Service aee942
unsigned int SerialCustomDataRates[] = { GEMPLUS_CUSTOM_DATA_RATES, 0 };
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					close_libusb_if_needed
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static void close_libusb_if_needed(void)
Packit Service aee942
{
Packit Service aee942
	int i, to_exit = TRUE;
Packit Service aee942
Packit Service aee942
	if (NULL == ctx)
Packit Service aee942
		return;
Packit Service aee942
Packit Service aee942
	/* if at least 1 reader is still in use we do not exit libusb */
Packit Service aee942
	for (i=0; i
Packit Service aee942
	{
Packit Service aee942
		if (usbDevice[i].dev_handle != NULL)
Packit Service aee942
			to_exit = FALSE;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (to_exit)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO1("libusb_exit");
Packit Service aee942
		libusb_exit(ctx);
Packit Service aee942
		ctx = NULL;
Packit Service aee942
	}
Packit Service aee942
} /* close_libusb_if_needed */
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					OpenUSB
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
status_t OpenUSB(unsigned int reader_index, /*@unused@*/ int Channel)
Packit Service aee942
{
Packit Service aee942
	(void)Channel;
Packit Service aee942
Packit Service aee942
	return OpenUSBByName(reader_index, NULL);
Packit Service aee942
} /* OpenUSB */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					OpenUSBByName
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
status_t OpenUSBByName(unsigned int reader_index, /*@null@*/ char *device)
Packit Service aee942
{
Packit Service aee942
	unsigned int alias;
Packit Service aee942
	struct libusb_device_handle *dev_handle;
Packit Service aee942
	char infofile[FILENAME_MAX];
Packit Service aee942
#ifndef __APPLE__
Packit Service aee942
	unsigned int device_vendor, device_product;
Packit Service aee942
	unsigned int device_bus = 0;
Packit Service aee942
	unsigned int device_addr = 0;
Packit Service aee942
#else
Packit Service aee942
	/* 100 ms delay */
Packit Service aee942
	struct timespec sleep_time = { 0, 100 * 1000 * 1000 };
Packit Service aee942
	int count_libusb = 10;
Packit Service aee942
#endif
Packit Service aee942
	int interface_number = -1;
Packit Service aee942
	int i;
Packit Service aee942
	static int previous_reader_index = -1;
Packit Service aee942
	libusb_device **devs, *dev;
Packit Service aee942
	ssize_t cnt;
Packit Service aee942
	list_t plist, *values, *ifdVendorID, *ifdProductID, *ifdFriendlyName;
Packit Service aee942
	int rv;
Packit Service aee942
	int claim_failed = FALSE;
Packit Service aee942
	int return_value = STATUS_SUCCESS;
Packit Service aee942
Packit Service aee942
	DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, device);
Packit Service aee942
Packit Service aee942
#ifndef __APPLE__
Packit Service aee942
	/* device name specified */
Packit Service aee942
	if (device)
Packit Service aee942
	{
Packit Service aee942
		char *dirname;
Packit Service aee942
Packit Service aee942
		/* format: usb:%04x/%04x, vendor, product */
Packit Service aee942
		if (strncmp("usb:", device, 4) != 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_CRITICAL2("device name does not start with \"usb:\": %s",
Packit Service aee942
				device);
Packit Service aee942
			return STATUS_UNSUCCESSFUL;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		if (sscanf(device, "usb:%x/%x", &device_vendor, &device_product) != 2)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_CRITICAL2("device name can't be parsed: %s", device);
Packit Service aee942
			return STATUS_UNSUCCESSFUL;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* format usb:%04x/%04x:libudev:%d:%s
Packit Service aee942
		 * with %d set to
Packit Service aee942
		 * 01 (or whatever the interface number is)
Packit Service aee942
		 * and %s set to
Packit Service aee942
		 * /dev/bus/usb/008/004
Packit Service aee942
		 */
Packit Service aee942
		if ((dirname = strstr(device, "libudev:")) != NULL)
Packit Service aee942
		{
Packit Service aee942
			/* convert the interface number, bus and device ids */
Packit Service aee942
			if (sscanf(dirname + 8, "%d:/dev/bus/usb/%d/%d", &interface_number, &device_bus, &device_addr) == 3) {
Packit Service aee942
				DEBUG_COMM2("interface_number: %d", interface_number);
Packit Service aee942
				DEBUG_COMM3("usb bus/device: %d/%d", device_bus, device_addr);
Packit Service aee942
			}
Packit Service aee942
		}
Packit Service aee942
		else
Packit Service aee942
		{
Packit Service aee942
			/* format usb:%04x/%04x:libusb-1.0:%d:%d:%d */
Packit Service aee942
			if ((dirname = strstr(device, "libusb-1.0:")) != NULL)
Packit Service aee942
			{
Packit Service aee942
				/* convert the interface number, bus and device ids */
Packit Service aee942
				if (sscanf(dirname + 11, "%d:%d:%d",
Packit Service aee942
					&device_bus, &device_addr, &interface_number) == 3)
Packit Service aee942
				{
Packit Service aee942
					DEBUG_COMM2("interface_number: %d", interface_number);
Packit Service aee942
					DEBUG_COMM3("usb bus/device: %d/%d", device_bus,
Packit Service aee942
						device_addr);
Packit Service aee942
				}
Packit Service aee942
			}
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	/* is the reader_index already used? */
Packit Service aee942
	if (usbDevice[reader_index].dev_handle != NULL)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL2("USB driver with index %X already in use",
Packit Service aee942
			reader_index);
Packit Service aee942
		return STATUS_UNSUCCESSFUL;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* Info.plist full patch filename */
Packit Service aee942
	(void)snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist",
Packit Service aee942
		PCSCLITE_HP_DROPDIR, BUNDLE);
Packit Service aee942
	DEBUG_INFO2("Using: %s", infofile);
Packit Service aee942
Packit Service aee942
	rv = bundleParse(infofile, &plist);
Packit Service aee942
	if (rv)
Packit Service aee942
		return STATUS_UNSUCCESSFUL;
Packit Service aee942
Packit Service aee942
#define GET_KEY(key, values) \
Packit Service aee942
	rv = LTPBundleFindValueWithKey(&plist, key, &values); \
Packit Service aee942
	if (rv) \
Packit Service aee942
	{ \
Packit Service aee942
		DEBUG_CRITICAL2("Value/Key not defined for " key " in %s", infofile); \
Packit Service aee942
		return_value = STATUS_UNSUCCESSFUL; \
Packit Service aee942
		goto end1; \
Packit Service aee942
	} \
Packit Service aee942
	else \
Packit Service aee942
		DEBUG_INFO2(key ": %s", (char *)list_get_at(values, 0));
Packit Service aee942
Packit Service aee942
	/* general driver info */
Packit Service aee942
	GET_KEY("ifdManufacturerString", values)
Packit Service aee942
	GET_KEY("ifdProductString", values)
Packit Service aee942
	GET_KEY("Copyright", values)
Packit Service aee942
Packit Service aee942
	if (NULL == ctx)
Packit Service aee942
	{
Packit Service aee942
		rv = libusb_init(&ctx;;
Packit Service aee942
		if (rv != 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_CRITICAL2("libusb_init failed: %s", libusb_error_name(rv));
Packit Service aee942
			return_value = STATUS_UNSUCCESSFUL;
Packit Service aee942
			goto end1;
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
#define GET_KEYS(key, values) \
Packit Service aee942
	rv = LTPBundleFindValueWithKey(&plist, key, values); \
Packit Service aee942
	if (rv) \
Packit Service aee942
	{ \
Packit Service aee942
		DEBUG_CRITICAL2("Value/Key not defined for " key " in %s", infofile); \
Packit Service aee942
		return_value = STATUS_UNSUCCESSFUL; \
Packit Service aee942
		goto end1; \
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	GET_KEYS("ifdVendorID", &ifdVendorID)
Packit Service aee942
	GET_KEYS("ifdProductID", &ifdProductID);
Packit Service aee942
	GET_KEYS("ifdFriendlyName", &ifdFriendlyName)
Packit Service aee942
Packit Service aee942
	/* The 3 lists do not have the same size */
Packit Service aee942
	if ((list_size(ifdVendorID) != list_size(ifdProductID))
Packit Service aee942
		|| (list_size(ifdVendorID) != list_size(ifdFriendlyName)))
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL2("Error parsing %s", infofile);
Packit Service aee942
		return_value = STATUS_UNSUCCESSFUL;
Packit Service aee942
		goto end1;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
#ifdef __APPLE__
Packit Service aee942
again_libusb:
Packit Service aee942
#endif
Packit Service aee942
	cnt = libusb_get_device_list(ctx, &devs);
Packit Service aee942
	if (cnt < 0)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL("libusb_get_device_list() failed\n");
Packit Service aee942
		return_value = STATUS_UNSUCCESSFUL;
Packit Service aee942
		goto end1;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* for any supported reader */
Packit Service aee942
	for (alias=0; alias
Packit Service aee942
	{
Packit Service aee942
		unsigned int vendorID, productID;
Packit Service aee942
		char *friendlyName;
Packit Service aee942
Packit Service aee942
		vendorID = strtoul(list_get_at(ifdVendorID, alias), NULL, 0);
Packit Service aee942
		productID = strtoul(list_get_at(ifdProductID, alias), NULL, 0);
Packit Service aee942
		friendlyName = list_get_at(ifdFriendlyName, alias);
Packit Service aee942
Packit Service aee942
#ifndef __APPLE__
Packit Service aee942
		/* the device was specified but is not the one we are trying to find */
Packit Service aee942
		if (device
Packit Service aee942
			&& (vendorID != device_vendor || productID != device_product))
Packit Service aee942
			continue;
Packit Service aee942
#else
Packit Service aee942
		/* Leopard puts the friendlyname in the device argument */
Packit Service aee942
		if (device && strcmp(device, friendlyName))
Packit Service aee942
			continue;
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
		/* for every device */
Packit Service aee942
		i = 0;
Packit Service aee942
		while ((dev = devs[i++]) != NULL)
Packit Service aee942
		{
Packit Service aee942
			struct libusb_device_descriptor desc;
Packit Service aee942
			struct libusb_config_descriptor *config_desc;
Packit Service aee942
			uint8_t bus_number = libusb_get_bus_number(dev);
Packit Service aee942
			uint8_t device_address = libusb_get_device_address(dev);
Packit Service aee942
Packit Service aee942
#ifndef __APPLE__
Packit Service aee942
			if ((device_bus || device_addr)
Packit Service aee942
				&& ((bus_number != device_bus)
Packit Service aee942
				|| (device_address != device_addr))) {
Packit Service aee942
				/* not USB the device we are looking for */
Packit Service aee942
				continue;
Packit Service aee942
			}
Packit Service aee942
#endif
Packit Service aee942
			DEBUG_COMM3("Try device: %d/%d", bus_number, device_address);
Packit Service aee942
Packit Service aee942
			int r = libusb_get_device_descriptor(dev, &desc);
Packit Service aee942
			if (r < 0)
Packit Service aee942
			{
Packit Service aee942
				DEBUG_INFO3("failed to get device descriptor for %d/%d",
Packit Service aee942
					bus_number, device_address);
Packit Service aee942
				continue;
Packit Service aee942
			}
Packit Service aee942
Packit Service aee942
			DEBUG_COMM3("vid/pid : %04X/%04X", desc.idVendor, desc.idProduct);
Packit Service aee942
Packit Service aee942
			if (desc.idVendor == vendorID && desc.idProduct == productID)
Packit Service aee942
			{
Packit Service aee942
				int already_used;
Packit Service aee942
				const struct libusb_interface *usb_interface = NULL;
Packit Service aee942
				int interface;
Packit Service aee942
				int num = 0;
Packit Service aee942
				const unsigned char *device_descriptor;
Packit Service aee942
				int readerID = (vendorID << 16) + productID;
Packit Service aee942
Packit Service aee942
#ifdef USE_COMPOSITE_AS_MULTISLOT
Packit Service aee942
				/* use the first CCID interface on first call */
Packit Service aee942
				static int static_interface = -1;
Packit Service aee942
				int max_interface_number = 2;
Packit Service aee942
Packit Service aee942
				/* simulate a composite device as when libudev is used */
Packit Service aee942
				if ((GEMALTOPROXDU == readerID)
Packit Service aee942
					|| (GEMALTOPROXSU == readerID)
Packit Service aee942
					|| (HID_OMNIKEY_5422 == readerID)
Packit Service aee942
					|| (FEITIANR502DUAL == readerID))
Packit Service aee942
				{
Packit Service aee942
						/*
Packit Service aee942
						 * We can't talk to the two CCID interfaces
Packit Service aee942
						 * at the same time (the reader enters a
Packit Service aee942
						 * dead lock). So we simulate a multi slot
Packit Service aee942
						 * reader. By default multi slot readers
Packit Service aee942
						 * can't use the slots at the same time. See
Packit Service aee942
						 * TAG_IFD_SLOT_THREAD_SAFE
Packit Service aee942
						 *
Packit Service aee942
						 * One side effect is that the two readers
Packit Service aee942
						 * are seen by pcscd as one reader so the
Packit Service aee942
						 * interface name is the same for the two.
Packit Service aee942
						 *
Packit Service aee942
	* So we have:
Packit Service aee942
	* 0: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 00
Packit Service aee942
	* 1: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 01
Packit Service aee942
	* instead of
Packit Service aee942
	* 0: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 00
Packit Service aee942
	* 1: Gemalto Prox-DU [Prox-DU Contactless_09A00795] (09A00795) 01 00
Packit Service aee942
						 */
Packit Service aee942
Packit Service aee942
					/* for the Gemalto Prox-DU/SU the interfaces are:
Packit Service aee942
					 * 0: Prox-DU HID (not used)
Packit Service aee942
					 * 1: Prox-DU Contactless (CCID)
Packit Service aee942
					 * 2: Prox-DU Contact (CCID)
Packit Service aee942
					 *
Packit Service aee942
					 * For the Feitian R502 the interfaces are:
Packit Service aee942
					 * 0: R502 Contactless Reader (CCID)
Packit Service aee942
					 * 1: R502 Contact Reader (CCID)
Packit Service aee942
					 * 2: R502 SAM1 Reader (CCID)
Packit Service aee942
					 *
Packit Service aee942
					 * For the HID Omnikey 5422 the interfaces are:
Packit Service aee942
					 * 0: OMNIKEY 5422CL Smartcard Reader
Packit Service aee942
					 * 1: OMNIKEY 5422 Smartcard Reader
Packit Service aee942
					 */
Packit Service aee942
					interface_number = static_interface;
Packit Service aee942
Packit Service aee942
					if (HID_OMNIKEY_5422 == readerID)
Packit Service aee942
						/* only 2 interfaces for this device */
Packit Service aee942
						max_interface_number = 1;
Packit Service aee942
				}
Packit Service aee942
#endif
Packit Service aee942
				/* is it already opened? */
Packit Service aee942
				already_used = FALSE;
Packit Service aee942
Packit Service aee942
				DEBUG_COMM3("Checking device: %d/%d",
Packit Service aee942
					bus_number, device_address);
Packit Service aee942
				for (r=0; r
Packit Service aee942
				{
Packit Service aee942
					if (usbDevice[r].dev_handle)
Packit Service aee942
					{
Packit Service aee942
						/* same bus, same address */
Packit Service aee942
						if (usbDevice[r].bus_number == bus_number
Packit Service aee942
							&& usbDevice[r].device_address == device_address)
Packit Service aee942
							already_used = TRUE;
Packit Service aee942
					}
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
				/* this reader is already managed by us */
Packit Service aee942
				if (already_used)
Packit Service aee942
				{
Packit Service aee942
					if ((previous_reader_index != -1)
Packit Service aee942
						&& usbDevice[previous_reader_index].dev_handle
Packit Service aee942
						&& (usbDevice[previous_reader_index].bus_number == bus_number)
Packit Service aee942
						&& (usbDevice[previous_reader_index].device_address == device_address)
Packit Service aee942
						&& usbDevice[previous_reader_index].ccid.bCurrentSlotIndex < usbDevice[previous_reader_index].ccid.bMaxSlotIndex)
Packit Service aee942
					{
Packit Service aee942
						/* we reuse the same device
Packit Service aee942
						 * and the reader is multi-slot */
Packit Service aee942
						usbDevice[reader_index] = usbDevice[previous_reader_index];
Packit Service aee942
						/* The other slots of GemCore SIM Pro firmware
Packit Service aee942
						 * 1.0 do not have the same data rates.
Packit Service aee942
						 * Firmware 2.0 do not have this limitation */
Packit Service aee942
						if ((GEMCOREPOSPRO == readerID)
Packit Service aee942
							|| ((GEMCORESIMPRO == readerID)
Packit Service aee942
							&& (usbDevice[reader_index].ccid.IFD_bcdDevice < 0x0200)))
Packit Service aee942
						{
Packit Service aee942
							/* Allocate a memory buffer that will be
Packit Service aee942
							 * released in CloseUSB() */
Packit Service aee942
							void *ptr = malloc(sizeof SerialCustomDataRates);
Packit Service aee942
							if (ptr)
Packit Service aee942
							{
Packit Service aee942
								memcpy(ptr, SerialCustomDataRates,
Packit Service aee942
									sizeof SerialCustomDataRates);
Packit Service aee942
							}
Packit Service aee942
Packit Service aee942
							usbDevice[reader_index].ccid.arrayOfSupportedDataRates = ptr;
Packit Service aee942
							usbDevice[reader_index].ccid.dwMaxDataRate = 125000;
Packit Service aee942
						}
Packit Service aee942
Packit Service aee942
						*usbDevice[reader_index].nb_opened_slots += 1;
Packit Service aee942
						usbDevice[reader_index].ccid.bCurrentSlotIndex++;
Packit Service aee942
						usbDevice[reader_index].ccid.dwSlotStatus =
Packit Service aee942
							IFD_ICC_PRESENT;
Packit Service aee942
						DEBUG_INFO2("Opening slot: %d",
Packit Service aee942
							usbDevice[reader_index].ccid.bCurrentSlotIndex);
Packit Service aee942
Packit Service aee942
						/* This is a multislot reader
Packit Service aee942
						 * Init the multislot stuff for this next slot */
Packit Service aee942
						usbDevice[reader_index].multislot_extension = Multi_CreateNextSlot(previous_reader_index);
Packit Service aee942
						goto end;
Packit Service aee942
					}
Packit Service aee942
					else
Packit Service aee942
					{
Packit Service aee942
						/* if an interface number is given by HAL we
Packit Service aee942
						 * continue with this device. */
Packit Service aee942
						if (-1 == interface_number)
Packit Service aee942
						{
Packit Service aee942
							DEBUG_INFO3("USB device %d/%d already in use."
Packit Service aee942
								" Checking next one.",
Packit Service aee942
								bus_number, device_address);
Packit Service aee942
							continue;
Packit Service aee942
						}
Packit Service aee942
					}
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
				DEBUG_COMM3("Trying to open USB bus/device: %d/%d",
Packit Service aee942
					bus_number, device_address);
Packit Service aee942
Packit Service aee942
				r = libusb_open(dev, &dev_handle);
Packit Service aee942
				if (r < 0)
Packit Service aee942
				{
Packit Service aee942
					DEBUG_CRITICAL4("Can't libusb_open(%d/%d): %s",
Packit Service aee942
						bus_number, device_address, libusb_error_name(r));
Packit Service aee942
Packit Service aee942
					continue;
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
again:
Packit Service aee942
				r = libusb_get_active_config_descriptor(dev, &config_desc);
Packit Service aee942
				if (r < 0)
Packit Service aee942
				{
Packit Service aee942
#ifdef __APPLE__
Packit Service aee942
					/* Some early Gemalto Ezio CB+ readers have
Packit Service aee942
					 * bDeviceClass, bDeviceSubClass and bDeviceProtocol set
Packit Service aee942
					 * to 0xFF (proprietary) instead of 0x00.
Packit Service aee942
					 *
Packit Service aee942
					 * So on Mac OS X the reader configuration is not done
Packit Service aee942
					 * by the OS/kernel and we do it ourself.
Packit Service aee942
					 */
Packit Service aee942
					if ((0xFF == desc.bDeviceClass)
Packit Service aee942
						&& (0xFF == desc.bDeviceSubClass)
Packit Service aee942
						&& (0xFF == desc.bDeviceProtocol))
Packit Service aee942
					{
Packit Service aee942
						r = libusb_set_configuration(dev_handle, 1);
Packit Service aee942
						if (r < 0)
Packit Service aee942
						{
Packit Service aee942
							(void)libusb_close(dev_handle);
Packit Service aee942
							DEBUG_CRITICAL4("Can't set configuration on %d/%d: %s",
Packit Service aee942
									bus_number, device_address,
Packit Service aee942
									libusb_error_name(r));
Packit Service aee942
							continue;
Packit Service aee942
						}
Packit Service aee942
					}
Packit Service aee942
Packit Service aee942
					/* recall */
Packit Service aee942
					r = libusb_get_active_config_descriptor(dev, &config_desc);
Packit Service aee942
					if (r < 0)
Packit Service aee942
					{
Packit Service aee942
#endif
Packit Service aee942
						(void)libusb_close(dev_handle);
Packit Service aee942
						DEBUG_CRITICAL4("Can't get config descriptor on %d/%d: %s",
Packit Service aee942
							bus_number, device_address, libusb_error_name(r));
Packit Service aee942
						continue;
Packit Service aee942
					}
Packit Service aee942
#ifdef __APPLE__
Packit Service aee942
				}
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
Packit Service aee942
				usb_interface = get_ccid_usb_interface(config_desc, &num);
Packit Service aee942
				if (usb_interface == NULL)
Packit Service aee942
				{
Packit Service aee942
					(void)libusb_close(dev_handle);
Packit Service aee942
					if (0 == num)
Packit Service aee942
						DEBUG_CRITICAL3("Can't find a CCID interface on %d/%d",
Packit Service aee942
							bus_number, device_address);
Packit Service aee942
					interface_number = -1;
Packit Service aee942
					continue;
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
				device_descriptor = get_ccid_device_descriptor(usb_interface);
Packit Service aee942
				if (NULL == device_descriptor)
Packit Service aee942
				{
Packit Service aee942
					(void)libusb_close(dev_handle);
Packit Service aee942
					DEBUG_CRITICAL3("Unable to find the device descriptor for %d/%d",
Packit Service aee942
						bus_number, device_address);
Packit Service aee942
					return_value = STATUS_UNSUCCESSFUL;
Packit Service aee942
					goto end2;
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
				interface = usb_interface->altsetting->bInterfaceNumber;
Packit Service aee942
				if (interface_number >= 0 && interface != interface_number)
Packit Service aee942
				{
Packit Service aee942
					/* an interface was specified and it is not the
Packit Service aee942
					 * current one */
Packit Service aee942
					DEBUG_INFO3("Found interface %d but expecting %d",
Packit Service aee942
						interface, interface_number);
Packit Service aee942
					DEBUG_INFO3("Wrong interface for USB device %d/%d."
Packit Service aee942
						" Checking next one.", bus_number, device_address);
Packit Service aee942
Packit Service aee942
					/* check for another CCID interface on the same device */
Packit Service aee942
					num++;
Packit Service aee942
Packit Service aee942
					goto again;
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
				r = libusb_claim_interface(dev_handle, interface);
Packit Service aee942
				if (r < 0)
Packit Service aee942
				{
Packit Service aee942
					(void)libusb_close(dev_handle);
Packit Service aee942
					DEBUG_CRITICAL4("Can't claim interface %d/%d: %s",
Packit Service aee942
						bus_number, device_address, libusb_error_name(r));
Packit Service aee942
					claim_failed = TRUE;
Packit Service aee942
					interface_number = -1;
Packit Service aee942
					continue;
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
				DEBUG_INFO4("Found Vendor/Product: %04X/%04X (%s)",
Packit Service aee942
					desc.idVendor, desc.idProduct, friendlyName);
Packit Service aee942
				DEBUG_INFO3("Using USB bus/device: %d/%d",
Packit Service aee942
					bus_number, device_address);
Packit Service aee942
Packit Service aee942
				/* check for firmware bugs */
Packit Service aee942
				if (ccid_check_firmware(&desc))
Packit Service aee942
				{
Packit Service aee942
					(void)libusb_close(dev_handle);
Packit Service aee942
					return_value = STATUS_UNSUCCESSFUL;
Packit Service aee942
					goto end2;
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
#ifdef USE_COMPOSITE_AS_MULTISLOT
Packit Service aee942
				if ((GEMALTOPROXDU == readerID)
Packit Service aee942
					|| (GEMALTOPROXSU == readerID)
Packit Service aee942
					|| (HID_OMNIKEY_5422 == readerID)
Packit Service aee942
					|| (FEITIANR502DUAL == readerID))
Packit Service aee942
				{
Packit Service aee942
					/* use the next interface for the next "slot" */
Packit Service aee942
					static_interface = interface + 1;
Packit Service aee942
Packit Service aee942
					/* reset for a next reader */
Packit Service aee942
					/* max interface number for all 3 readers is 2 */
Packit Service aee942
					if (static_interface > max_interface_number)
Packit Service aee942
						static_interface = -1;
Packit Service aee942
				}
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
				/* Get Endpoints values*/
Packit Service aee942
				(void)get_end_points(config_desc, &usbDevice[reader_index], num);
Packit Service aee942
Packit Service aee942
				/* store device information */
Packit Service aee942
				usbDevice[reader_index].dev_handle = dev_handle;
Packit Service aee942
				usbDevice[reader_index].bus_number = bus_number;
Packit Service aee942
				usbDevice[reader_index].device_address = device_address;
Packit Service aee942
				usbDevice[reader_index].interface = interface;
Packit Service aee942
				usbDevice[reader_index].real_nb_opened_slots = 1;
Packit Service aee942
				usbDevice[reader_index].nb_opened_slots = &usbDevice[reader_index].real_nb_opened_slots;
Packit Service aee942
				usbDevice[reader_index].polling_transfer = NULL;
Packit Service aee942
Packit Service aee942
				/* CCID common informations */
Packit Service aee942
				usbDevice[reader_index].ccid.real_bSeq = 0;
Packit Service aee942
				usbDevice[reader_index].ccid.pbSeq = &usbDevice[reader_index].ccid.real_bSeq;
Packit Service aee942
				usbDevice[reader_index].ccid.readerID =
Packit Service aee942
					(desc.idVendor << 16) + desc.idProduct;
Packit Service aee942
				usbDevice[reader_index].ccid.dwFeatures = dw2i(device_descriptor, 40);
Packit Service aee942
				usbDevice[reader_index].ccid.wLcdLayout =
Packit Service aee942
					(device_descriptor[51] << 8) + device_descriptor[50];
Packit Service aee942
				usbDevice[reader_index].ccid.bPINSupport = device_descriptor[52];
Packit Service aee942
				usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = dw2i(device_descriptor, 44);
Packit Service aee942
				usbDevice[reader_index].ccid.dwMaxIFSD = dw2i(device_descriptor, 28);
Packit Service aee942
				usbDevice[reader_index].ccid.dwDefaultClock = dw2i(device_descriptor, 10);
Packit Service aee942
				usbDevice[reader_index].ccid.dwMaxDataRate = dw2i(device_descriptor, 23);
Packit Service aee942
				usbDevice[reader_index].ccid.bMaxSlotIndex = device_descriptor[4];
Packit Service aee942
				usbDevice[reader_index].ccid.bCurrentSlotIndex = 0;
Packit Service aee942
				usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT;
Packit Service aee942
				if (device_descriptor[27])
Packit Service aee942
					usbDevice[reader_index].ccid.arrayOfSupportedDataRates = get_data_rates(reader_index, config_desc, num);
Packit Service aee942
				else
Packit Service aee942
				{
Packit Service aee942
					usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL;
Packit Service aee942
					DEBUG_INFO1("bNumDataRatesSupported is 0");
Packit Service aee942
				}
Packit Service aee942
				usbDevice[reader_index].ccid.bInterfaceProtocol = usb_interface->altsetting->bInterfaceProtocol;
Packit Service aee942
				usbDevice[reader_index].ccid.bNumEndpoints = usb_interface->altsetting->bNumEndpoints;
Packit Service aee942
				usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT;
Packit Service aee942
				usbDevice[reader_index].ccid.bVoltageSupport = device_descriptor[5];
Packit Service aee942
				usbDevice[reader_index].ccid.sIFD_serial_number = NULL;
Packit Service aee942
				usbDevice[reader_index].ccid.gemalto_firmware_features = NULL;
Packit Service aee942
#ifdef ENABLE_ZLP
Packit Service aee942
				usbDevice[reader_index].ccid.zlp = FALSE;
Packit Service aee942
#endif
Packit Service aee942
				if (desc.iSerialNumber)
Packit Service aee942
				{
Packit Service aee942
					unsigned char serial[128];
Packit Service aee942
					int ret;
Packit Service aee942
Packit Service aee942
					ret = libusb_get_string_descriptor_ascii(dev_handle,
Packit Service aee942
							desc.iSerialNumber, serial,
Packit Service aee942
							sizeof(serial));
Packit Service aee942
					if (ret > 0)
Packit Service aee942
						usbDevice[reader_index].ccid.sIFD_serial_number
Packit Service aee942
							= strdup((char *)serial);
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
				usbDevice[reader_index].ccid.sIFD_iManufacturer = NULL;
Packit Service aee942
				if (desc.iManufacturer)
Packit Service aee942
				{
Packit Service aee942
					unsigned char iManufacturer[128];
Packit Service aee942
					int ret;
Packit Service aee942
Packit Service aee942
					ret = libusb_get_string_descriptor_ascii(dev_handle,
Packit Service aee942
							desc.iManufacturer, iManufacturer,
Packit Service aee942
							sizeof(iManufacturer));
Packit Service aee942
					if (ret > 0)
Packit Service aee942
						usbDevice[reader_index].ccid.sIFD_iManufacturer
Packit Service aee942
							= strdup((char *)iManufacturer);
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
				usbDevice[reader_index].ccid.IFD_bcdDevice = desc.bcdDevice;
Packit Service aee942
Packit Service aee942
				/* If this is a multislot reader, init the multislot stuff */
Packit Service aee942
				if (usbDevice[reader_index].ccid.bMaxSlotIndex)
Packit Service aee942
					usbDevice[reader_index].multislot_extension = Multi_CreateFirstSlot(reader_index);
Packit Service aee942
				else
Packit Service aee942
					usbDevice[reader_index].multislot_extension = NULL;
Packit Service aee942
Packit Service aee942
				goto end;
Packit Service aee942
			}
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
end:
Packit Service aee942
	if (usbDevice[reader_index].dev_handle == NULL)
Packit Service aee942
	{
Packit Service aee942
		/* free the libusb allocated list & devices */
Packit Service aee942
		libusb_free_device_list(devs, 1);
Packit Service aee942
Packit Service aee942
#ifdef __APPLE__
Packit Service aee942
		/* give some time to libusb to detect the new USB devices on Mac OS X */
Packit Service aee942
		if (count_libusb > 0)
Packit Service aee942
		{
Packit Service aee942
			count_libusb--;
Packit Service aee942
			DEBUG_INFO2("Wait after libusb: %d", count_libusb);
Packit Service aee942
			nanosleep(&sleep_time, NULL);
Packit Service aee942
Packit Service aee942
			goto again_libusb;
Packit Service aee942
		}
Packit Service aee942
#endif
Packit Service aee942
		/* failed */
Packit Service aee942
		close_libusb_if_needed();
Packit Service aee942
Packit Service aee942
		if (claim_failed)
Packit Service aee942
			return STATUS_COMM_ERROR;
Packit Service aee942
		DEBUG_INFO1("Device not found?");
Packit Service aee942
		return STATUS_NO_SUCH_DEVICE;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* memorise the current reader_index so we can detect
Packit Service aee942
	 * a new OpenUSBByName on a multi slot reader */
Packit Service aee942
	previous_reader_index = reader_index;
Packit Service aee942
Packit Service aee942
end2:
Packit Service aee942
	/* free the libusb allocated list & devices */
Packit Service aee942
	libusb_free_device_list(devs, 1);
Packit Service aee942
Packit Service aee942
end1:
Packit Service aee942
	/* free bundle list */
Packit Service aee942
	bundleRelease(&plist);
Packit Service aee942
Packit Service aee942
	if (return_value != STATUS_SUCCESS)
Packit Service aee942
		close_libusb_if_needed();
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* OpenUSBByName */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					WriteUSB
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
status_t WriteUSB(unsigned int reader_index, unsigned int length,
Packit Service aee942
	unsigned char *buffer)
Packit Service aee942
{
Packit Service aee942
	int rv;
Packit Service aee942
	int actual_length;
Packit Service aee942
	char debug_header[] = "-> 121234 ";
Packit Service aee942
Packit Service aee942
	(void)snprintf(debug_header, sizeof(debug_header), "-> %06X ",
Packit Service aee942
		(int)reader_index);
Packit Service aee942
Packit Service aee942
#ifdef ENABLE_ZLP
Packit Service aee942
	if (usbDevice[reader_index].ccid.zlp)
Packit Service aee942
	{ /* Zero Length Packet */
Packit Service aee942
		int dummy_length;
Packit Service aee942
Packit Service aee942
		/* try to read a ZLP so transfer length = 0
Packit Service aee942
		 * timeout of 10 ms */
Packit Service aee942
		(void)libusb_bulk_transfer(usbDevice[reader_index].dev_handle,
Packit Service aee942
			usbDevice[reader_index].bulk_in, NULL, 0, &dummy_length, 10);
Packit Service aee942
	}
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	DEBUG_XXD(debug_header, buffer, length);
Packit Service aee942
Packit Service aee942
	rv = libusb_bulk_transfer(usbDevice[reader_index].dev_handle,
Packit Service aee942
		usbDevice[reader_index].bulk_out, buffer, length,
Packit Service aee942
		&actual_length, USB_WRITE_TIMEOUT);
Packit Service aee942
Packit Service aee942
	if (rv < 0)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL5("write failed (%d/%d): %d %s",
Packit Service aee942
			usbDevice[reader_index].bus_number,
Packit Service aee942
			usbDevice[reader_index].device_address, rv, libusb_error_name(rv));
Packit Service aee942
Packit Service aee942
		if (LIBUSB_ERROR_NO_DEVICE == rv)
Packit Service aee942
			return STATUS_NO_SUCH_DEVICE;
Packit Service aee942
Packit Service aee942
		return STATUS_UNSUCCESSFUL;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return STATUS_SUCCESS;
Packit Service aee942
} /* WriteUSB */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					ReadUSB
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
status_t ReadUSB(unsigned int reader_index, unsigned int * length,
Packit Service aee942
	unsigned char *buffer)
Packit Service aee942
{
Packit Service aee942
	int rv;
Packit Service aee942
	int actual_length;
Packit Service aee942
	char debug_header[] = "<- 121234 ";
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
	int duplicate_frame = 0;
Packit Service aee942
Packit Service aee942
read_again:
Packit Service aee942
	(void)snprintf(debug_header, sizeof(debug_header), "<- %06X ",
Packit Service aee942
		(int)reader_index);
Packit Service aee942
Packit Service aee942
	rv = libusb_bulk_transfer(usbDevice[reader_index].dev_handle,
Packit Service aee942
		usbDevice[reader_index].bulk_in, buffer, *length,
Packit Service aee942
		&actual_length, usbDevice[reader_index].ccid.readTimeout);
Packit Service aee942
Packit Service aee942
	if (rv < 0)
Packit Service aee942
	{
Packit Service aee942
		*length = 0;
Packit Service aee942
		DEBUG_CRITICAL5("read failed (%d/%d): %d %s",
Packit Service aee942
			usbDevice[reader_index].bus_number,
Packit Service aee942
			usbDevice[reader_index].device_address, rv, libusb_error_name(rv));
Packit Service aee942
Packit Service aee942
		if (LIBUSB_ERROR_NO_DEVICE == rv)
Packit Service aee942
			return STATUS_NO_SUCH_DEVICE;
Packit Service aee942
Packit Service aee942
		return STATUS_UNSUCCESSFUL;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	*length = actual_length;
Packit Service aee942
Packit Service aee942
	DEBUG_XXD(debug_header, buffer, *length);
Packit Service aee942
Packit Service aee942
#define BSEQ_OFFSET 6
Packit Service aee942
	if ((*length >= BSEQ_OFFSET)
Packit Service aee942
		&& (buffer[BSEQ_OFFSET] < *ccid_descriptor->pbSeq -1))
Packit Service aee942
	{
Packit Service aee942
		duplicate_frame++;
Packit Service aee942
		if (duplicate_frame > 10)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_CRITICAL("Too many duplicate frame detected");
Packit Service aee942
			return STATUS_UNSUCCESSFUL;
Packit Service aee942
		}
Packit Service aee942
		DEBUG_INFO1("Duplicate frame detected");
Packit Service aee942
		goto read_again;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return STATUS_SUCCESS;
Packit Service aee942
} /* ReadUSB */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CloseUSB
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
status_t CloseUSB(unsigned int reader_index)
Packit Service aee942
{
Packit Service aee942
	/* device not opened */
Packit Service aee942
	if (usbDevice[reader_index].dev_handle == NULL)
Packit Service aee942
		return STATUS_UNSUCCESSFUL;
Packit Service aee942
Packit Service aee942
	DEBUG_COMM3("Closing USB device: %d/%d",
Packit Service aee942
		usbDevice[reader_index].bus_number,
Packit Service aee942
		usbDevice[reader_index].device_address);
Packit Service aee942
Packit Service aee942
	/* one slot closed */
Packit Service aee942
	(*usbDevice[reader_index].nb_opened_slots)--;
Packit Service aee942
Packit Service aee942
	/* release the allocated ressources for the last slot only */
Packit Service aee942
	if (0 == *usbDevice[reader_index].nb_opened_slots)
Packit Service aee942
	{
Packit Service aee942
		struct usbDevice_MultiSlot_Extension *msExt;
Packit Service aee942
Packit Service aee942
		DEBUG_COMM("Last slot closed. Release resources");
Packit Service aee942
Packit Service aee942
		msExt = usbDevice[reader_index].multislot_extension;
Packit Service aee942
		/* If this is a multislot reader, close using the multislot stuff */
Packit Service aee942
		if (msExt)
Packit Service aee942
		{
Packit Service aee942
			/* terminate the interrupt waiter thread */
Packit Service aee942
			Multi_PollingTerminate(msExt);
Packit Service aee942
Packit Service aee942
			/* wait for the thread to actually terminate */
Packit Service aee942
			pthread_join(msExt->thread_proc, NULL);
Packit Service aee942
Packit Service aee942
			/* release the shared objects */
Packit Service aee942
			pthread_cond_destroy(&msExt->condition);
Packit Service aee942
			pthread_mutex_destroy(&msExt->mutex);
Packit Service aee942
Packit Service aee942
			/* Deallocate the extension itself */
Packit Service aee942
			free(msExt);
Packit Service aee942
Packit Service aee942
			/* Stop the slot */
Packit Service aee942
			usbDevice[reader_index].multislot_extension = NULL;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		if (usbDevice[reader_index].ccid.gemalto_firmware_features)
Packit Service aee942
			free(usbDevice[reader_index].ccid.gemalto_firmware_features);
Packit Service aee942
Packit Service aee942
		if (usbDevice[reader_index].ccid.sIFD_serial_number)
Packit Service aee942
			free(usbDevice[reader_index].ccid.sIFD_serial_number);
Packit Service aee942
Packit Service aee942
		if (usbDevice[reader_index].ccid.sIFD_iManufacturer)
Packit Service aee942
			free(usbDevice[reader_index].ccid.sIFD_iManufacturer);
Packit Service aee942
Packit Service aee942
		if (usbDevice[reader_index].ccid.arrayOfSupportedDataRates)
Packit Service aee942
			free(usbDevice[reader_index].ccid.arrayOfSupportedDataRates);
Packit Service aee942
Packit Service aee942
		(void)libusb_release_interface(usbDevice[reader_index].dev_handle,
Packit Service aee942
			usbDevice[reader_index].interface);
Packit Service aee942
		(void)libusb_close(usbDevice[reader_index].dev_handle);
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* mark the resource unused */
Packit Service aee942
	usbDevice[reader_index].dev_handle = NULL;
Packit Service aee942
	usbDevice[reader_index].interface = 0;
Packit Service aee942
Packit Service aee942
	close_libusb_if_needed();
Packit Service aee942
Packit Service aee942
	return STATUS_SUCCESS;
Packit Service aee942
} /* CloseUSB */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					get_ccid_descriptor
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
_ccid_descriptor *get_ccid_descriptor(unsigned int reader_index)
Packit Service aee942
{
Packit Service aee942
	return &usbDevice[reader_index].ccid;
Packit Service aee942
} /* get_ccid_descriptor */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					get_ccid_device_descriptor
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
const unsigned char *get_ccid_device_descriptor(const struct libusb_interface *usb_interface)
Packit Service aee942
{
Packit Service aee942
#ifdef O2MICRO_OZ776_PATCH
Packit Service aee942
	uint8_t last_endpoint;
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	if (54 == usb_interface->altsetting->extra_length)
Packit Service aee942
		return usb_interface->altsetting->extra;
Packit Service aee942
Packit Service aee942
	if (0 != usb_interface->altsetting->extra_length)
Packit Service aee942
	{
Packit Service aee942
		/* If extra_length is zero, the descriptor might be at
Packit Service aee942
		 * the end, but if it's not zero, we have a
Packit Service aee942
		 * problem. */
Packit Service aee942
		DEBUG_CRITICAL2("Extra field has a wrong length: %d",
Packit Service aee942
			usb_interface->altsetting->extra_length);
Packit Service aee942
		return NULL;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
#ifdef O2MICRO_OZ776_PATCH
Packit Service aee942
	/* Some devices, such as the Oz776, Reiner SCT and bludrive II
Packit Service aee942
	 * report the device descriptor at the end of the endpoint
Packit Service aee942
	 * descriptors; to support those, look for it at the end as well.
Packit Service aee942
	 */
Packit Service aee942
	last_endpoint = usb_interface->altsetting->bNumEndpoints-1;
Packit Service aee942
	if (usb_interface->altsetting->endpoint
Packit Service aee942
		&& usb_interface->altsetting->endpoint[last_endpoint].extra_length == 54)
Packit Service aee942
		return usb_interface->altsetting->endpoint[last_endpoint].extra;
Packit Service aee942
#else
Packit Service aee942
	DEBUG_CRITICAL2("Extra field has a wrong length: %d",
Packit Service aee942
		usb_interface->altsetting->extra_length);
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	return NULL;
Packit Service aee942
} /* get_ccid_device_descriptor */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					get_end_points
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static int get_end_points(struct libusb_config_descriptor *desc,
Packit Service aee942
	_usbDevice *usbdevice, int num)
Packit Service aee942
{
Packit Service aee942
	int i;
Packit Service aee942
	int bEndpointAddress;
Packit Service aee942
	const struct libusb_interface *usb_interface;
Packit Service aee942
Packit Service aee942
	usb_interface = get_ccid_usb_interface(desc, &num);
Packit Service aee942
Packit Service aee942
	/*
Packit Service aee942
	 * 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out
Packit Service aee942
	 */
Packit Service aee942
	for (i=0; i<usb_interface->altsetting->bNumEndpoints; i++)
Packit Service aee942
	{
Packit Service aee942
		/* interrupt end point (if available) */
Packit Service aee942
		if (usb_interface->altsetting->endpoint[i].bmAttributes
Packit Service aee942
			== LIBUSB_TRANSFER_TYPE_INTERRUPT)
Packit Service aee942
		{
Packit Service aee942
			usbdevice->interrupt =
Packit Service aee942
				usb_interface->altsetting->endpoint[i].bEndpointAddress;
Packit Service aee942
			continue;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		if (usb_interface->altsetting->endpoint[i].bmAttributes
Packit Service aee942
			!= LIBUSB_TRANSFER_TYPE_BULK)
Packit Service aee942
			continue;
Packit Service aee942
Packit Service aee942
		bEndpointAddress =
Packit Service aee942
			usb_interface->altsetting->endpoint[i].bEndpointAddress;
Packit Service aee942
Packit Service aee942
		if ((bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
Packit Service aee942
			== LIBUSB_ENDPOINT_IN)
Packit Service aee942
			usbdevice->bulk_in = bEndpointAddress;
Packit Service aee942
Packit Service aee942
		if ((bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
Packit Service aee942
			== LIBUSB_ENDPOINT_OUT)
Packit Service aee942
			usbdevice->bulk_out = bEndpointAddress;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return 0;
Packit Service aee942
} /* get_end_points */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					get_ccid_usb_interface
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
/*@null@*/ EXTERNAL const struct libusb_interface * get_ccid_usb_interface(
Packit Service aee942
	struct libusb_config_descriptor *desc, int *num)
Packit Service aee942
{
Packit Service aee942
	const struct libusb_interface *usb_interface = NULL;
Packit Service aee942
	int i;
Packit Service aee942
Packit Service aee942
	/* if multiple interfaces use the first one with CCID class type */
Packit Service aee942
	for (i = *num; i < desc->bNumInterfaces; i++)
Packit Service aee942
	{
Packit Service aee942
		/* CCID Class? */
Packit Service aee942
		if (desc->interface[i].altsetting->bInterfaceClass == 0xb
Packit Service aee942
#ifdef ALLOW_PROPRIETARY_CLASS
Packit Service aee942
			|| (desc->interface[i].altsetting->bInterfaceClass == 0xff
Packit Service aee942
			&& 54 == desc->interface[i].altsetting->extra_length)
Packit Service aee942
#endif
Packit Service aee942
			)
Packit Service aee942
		{
Packit Service aee942
			usb_interface = &desc->interface[i];
Packit Service aee942
			/* store the interface number for further reference */
Packit Service aee942
			*num = i;
Packit Service aee942
			break;
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return usb_interface;
Packit Service aee942
} /* get_ccid_usb_interface */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					ccid_check_firmware
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
int ccid_check_firmware(struct libusb_device_descriptor *desc)
Packit Service aee942
{
Packit Service aee942
	unsigned int i;
Packit Service aee942
Packit Service aee942
	for (i=0; i
Packit Service aee942
	{
Packit Service aee942
		if (desc->idVendor != Bogus_firmwares[i].vendor)
Packit Service aee942
			continue;
Packit Service aee942
Packit Service aee942
		if (desc->idProduct != Bogus_firmwares[i].product)
Packit Service aee942
			continue;
Packit Service aee942
Packit Service aee942
		/* firmware too old and buggy */
Packit Service aee942
		if (desc->bcdDevice < Bogus_firmwares[i].firmware)
Packit Service aee942
		{
Packit Service aee942
			if (DriverOptions & DRIVER_OPTION_USE_BOGUS_FIRMWARE)
Packit Service aee942
			{
Packit Service aee942
				DEBUG_INFO3("Firmware (%X.%02X) is bogus! but you choosed to use it",
Packit Service aee942
					desc->bcdDevice >> 8, desc->bcdDevice & 0xFF);
Packit Service aee942
				return FALSE;
Packit Service aee942
			}
Packit Service aee942
			else
Packit Service aee942
			{
Packit Service aee942
				DEBUG_CRITICAL3("Firmware (%X.%02X) is bogus! Upgrade the reader firmware or get a new reader.",
Packit Service aee942
					desc->bcdDevice >> 8, desc->bcdDevice & 0xFF);
Packit Service aee942
				return TRUE;
Packit Service aee942
			}
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* by default the firmware is not bogus */
Packit Service aee942
	return FALSE;
Packit Service aee942
} /* ccid_check_firmware */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					get_data_rates
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static unsigned int *get_data_rates(unsigned int reader_index,
Packit Service aee942
	struct libusb_config_descriptor *desc, int num)
Packit Service aee942
{
Packit Service aee942
	int n, i, len;
Packit Service aee942
	unsigned char buffer[256*sizeof(int)];	/* maximum is 256 records */
Packit Service aee942
	unsigned int *uint_array;
Packit Service aee942
Packit Service aee942
	/* See CCID 3.7.3 page 25 */
Packit Service aee942
	n = ControlUSB(reader_index,
Packit Service aee942
		0xA1, /* request type */
Packit Service aee942
		0x03, /* GET_DATA_RATES */
Packit Service aee942
		0x00, /* value */
Packit Service aee942
		buffer, sizeof(buffer));
Packit Service aee942
Packit Service aee942
	/* we got an error? */
Packit Service aee942
	if (n <= 0)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO2("IFD does not support GET_DATA_RATES request: %d", n);
Packit Service aee942
		return NULL;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* we got a strange value */
Packit Service aee942
	if (n % 4)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO2("Wrong GET DATA RATES size: %d", n);
Packit Service aee942
		return NULL;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* allocate the buffer (including the end marker) */
Packit Service aee942
	n /= sizeof(int);
Packit Service aee942
Packit Service aee942
	/* we do not get the expected number of data rates */
Packit Service aee942
	len = get_ccid_device_descriptor(get_ccid_usb_interface(desc, &num))[27]; /* bNumDataRatesSupported */
Packit Service aee942
	if ((n != len) && len)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO3("Got %d data rates but was expecting %d", n, len);
Packit Service aee942
Packit Service aee942
		/* we got more data than expected */
Packit Service aee942
		if (n > len)
Packit Service aee942
			n = len;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	uint_array = calloc(n+1, sizeof(uint_array[0]));
Packit Service aee942
	if (NULL == uint_array)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL("Memory allocation failed");
Packit Service aee942
		return NULL;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* convert in correct endianess */
Packit Service aee942
	for (i=0; i
Packit Service aee942
	{
Packit Service aee942
		uint_array[i] = dw2i(buffer, i*4);
Packit Service aee942
		DEBUG_INFO2("declared: %d bps", uint_array[i]);
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* end of array marker */
Packit Service aee942
	uint_array[i] = 0;
Packit Service aee942
Packit Service aee942
	return uint_array;
Packit Service aee942
} /* get_data_rates */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					ControlUSB
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
int ControlUSB(int reader_index, int requesttype, int request, int value,
Packit Service aee942
	unsigned char *bytes, unsigned int size)
Packit Service aee942
{
Packit Service aee942
	int ret;
Packit Service aee942
Packit Service aee942
	DEBUG_COMM2("request: 0x%02X", request);
Packit Service aee942
Packit Service aee942
	if (0 == (requesttype & 0x80))
Packit Service aee942
		DEBUG_XXD("send: ", bytes, size);
Packit Service aee942
Packit Service aee942
	ret = libusb_control_transfer(usbDevice[reader_index].dev_handle,
Packit Service aee942
		requesttype, request, value, usbDevice[reader_index].interface,
Packit Service aee942
		bytes, size, usbDevice[reader_index].ccid.readTimeout);
Packit Service aee942
Packit Service aee942
	if (ret < 0)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL5("control failed (%d/%d): %d %s",
Packit Service aee942
			usbDevice[reader_index].bus_number,
Packit Service aee942
			usbDevice[reader_index].device_address, ret, libusb_error_name(ret));
Packit Service aee942
Packit Service aee942
		return ret;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (requesttype & 0x80)
Packit Service aee942
		DEBUG_XXD("receive: ", bytes, ret);
Packit Service aee942
Packit Service aee942
	return ret;
Packit Service aee942
} /* ControlUSB */
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					Transfer is complete
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static void bulk_transfer_cb(struct libusb_transfer *transfer)
Packit Service aee942
{
Packit Service aee942
	int *completed = transfer->user_data;
Packit Service aee942
	*completed = 1;
Packit Service aee942
	/* caller interprets results and frees transfer */
Packit Service aee942
}
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					InterruptRead
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
int InterruptRead(int reader_index, int timeout /* in ms */)
Packit Service aee942
{
Packit Service aee942
	int ret, actual_length;
Packit Service aee942
	int return_value = IFD_SUCCESS;
Packit Service aee942
	unsigned char buffer[8];
Packit Service aee942
	struct libusb_transfer *transfer;
Packit Service aee942
	int completed = 0;
Packit Service aee942
Packit Service aee942
	/* Multislot reader: redirect to Multi_InterrupRead */
Packit Service aee942
	if (usbDevice[reader_index].multislot_extension != NULL)
Packit Service aee942
		return Multi_InterruptRead(reader_index, timeout);
Packit Service aee942
Packit Service aee942
	DEBUG_PERIODIC2("before (%d)", reader_index);
Packit Service aee942
Packit Service aee942
	transfer = libusb_alloc_transfer(0);
Packit Service aee942
	if (NULL == transfer)
Packit Service aee942
		return LIBUSB_ERROR_NO_MEM;
Packit Service aee942
Packit Service aee942
	libusb_fill_bulk_transfer(transfer,
Packit Service aee942
		usbDevice[reader_index].dev_handle,
Packit Service aee942
		usbDevice[reader_index].interrupt, buffer, sizeof(buffer),
Packit Service aee942
		bulk_transfer_cb, &completed, timeout);
Packit Service aee942
	transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
Packit Service aee942
Packit Service aee942
	ret = libusb_submit_transfer(transfer);
Packit Service aee942
	if (ret < 0) {
Packit Service aee942
		libusb_free_transfer(transfer);
Packit Service aee942
		DEBUG_CRITICAL2("libusb_submit_transfer failed: %s",
Packit Service aee942
			libusb_error_name(ret));
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	usbDevice[reader_index].polling_transfer = transfer;
Packit Service aee942
Packit Service aee942
	while (!completed)
Packit Service aee942
	{
Packit Service aee942
		ret = libusb_handle_events_completed(ctx, &completed);
Packit Service aee942
		if (ret < 0)
Packit Service aee942
		{
Packit Service aee942
			if (ret == LIBUSB_ERROR_INTERRUPTED)
Packit Service aee942
				continue;
Packit Service aee942
			libusb_cancel_transfer(transfer);
Packit Service aee942
			while (!completed)
Packit Service aee942
				if (libusb_handle_events_completed(ctx, &completed) < 0)
Packit Service aee942
					break;
Packit Service aee942
			libusb_free_transfer(transfer);
Packit Service aee942
			DEBUG_CRITICAL2("libusb_handle_events failed: %s",
Packit Service aee942
				libusb_error_name(ret));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	actual_length = transfer->actual_length;
Packit Service aee942
	ret = transfer->status;
Packit Service aee942
Packit Service aee942
	usbDevice[reader_index].polling_transfer = NULL;
Packit Service aee942
	libusb_free_transfer(transfer);
Packit Service aee942
Packit Service aee942
	DEBUG_PERIODIC3("after (%d) (%d)", reader_index, ret);
Packit Service aee942
Packit Service aee942
	switch (ret)
Packit Service aee942
	{
Packit Service aee942
		case LIBUSB_TRANSFER_COMPLETED:
Packit Service aee942
			DEBUG_XXD("NotifySlotChange: ", buffer, actual_length);
Packit Service aee942
			break;
Packit Service aee942
Packit Service aee942
		case LIBUSB_TRANSFER_TIMED_OUT:
Packit Service aee942
			break;
Packit Service aee942
Packit Service aee942
		default:
Packit Service aee942
			/* if libusb_interrupt_transfer() times out we get EILSEQ or EAGAIN */
Packit Service aee942
			DEBUG_COMM4("InterruptRead (%d/%d): %s",
Packit Service aee942
				usbDevice[reader_index].bus_number,
Packit Service aee942
				usbDevice[reader_index].device_address, libusb_error_name(ret));
Packit Service aee942
			return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* InterruptRead */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					Stop the async loop
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
void InterruptStop(int reader_index)
Packit Service aee942
{
Packit Service aee942
	struct libusb_transfer *transfer;
Packit Service aee942
Packit Service aee942
	/* Multislot reader: redirect to Multi_InterrupStop */
Packit Service aee942
	if (usbDevice[reader_index].multislot_extension != NULL)
Packit Service aee942
	{
Packit Service aee942
		Multi_InterruptStop(reader_index);
Packit Service aee942
		return;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	transfer = usbDevice[reader_index].polling_transfer;
Packit Service aee942
	usbDevice[reader_index].polling_transfer = NULL;
Packit Service aee942
	if (transfer)
Packit Service aee942
	{
Packit Service aee942
		int ret;
Packit Service aee942
Packit Service aee942
		ret = libusb_cancel_transfer(transfer);
Packit Service aee942
		if (ret < 0)
Packit Service aee942
			DEBUG_CRITICAL2("libusb_cancel_transfer failed: %d", ret);
Packit Service aee942
	}
Packit Service aee942
} /* InterruptStop */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					Multi_PollingProc
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static void *Multi_PollingProc(void *p_ext)
Packit Service aee942
{
Packit Service aee942
	struct usbDevice_MultiSlot_Extension *msExt = p_ext;
Packit Service aee942
	int rv, status, actual_length;
Packit Service aee942
	unsigned char buffer[CCID_INTERRUPT_SIZE];
Packit Service aee942
	struct libusb_transfer *transfer;
Packit Service aee942
	int completed;
Packit Service aee942
Packit Service aee942
	DEBUG_COMM3("Multi_PollingProc (%d/%d): thread starting",
Packit Service aee942
		usbDevice[msExt->reader_index].bus_number,
Packit Service aee942
		usbDevice[msExt->reader_index].device_address);
Packit Service aee942
Packit Service aee942
	rv = 0;
Packit Service aee942
	while (!msExt->terminated)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_COMM3("Multi_PollingProc (%d/%d): waiting",
Packit Service aee942
			usbDevice[msExt->reader_index].bus_number,
Packit Service aee942
			usbDevice[msExt->reader_index].device_address);
Packit Service aee942
Packit Service aee942
		transfer = libusb_alloc_transfer(0);
Packit Service aee942
		if (NULL == transfer)
Packit Service aee942
		{
Packit Service aee942
			rv = LIBUSB_ERROR_NO_MEM;
Packit Service aee942
			DEBUG_COMM2("libusb_alloc_transfer err %d", rv);
Packit Service aee942
			break;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		libusb_fill_bulk_transfer(transfer,
Packit Service aee942
			usbDevice[msExt->reader_index].dev_handle,
Packit Service aee942
			usbDevice[msExt->reader_index].interrupt,
Packit Service aee942
			buffer, CCID_INTERRUPT_SIZE,
Packit Service aee942
			bulk_transfer_cb, &completed, 0); /* No timeout ! */
Packit Service aee942
Packit Service aee942
		transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
Packit Service aee942
Packit Service aee942
		rv = libusb_submit_transfer(transfer);
Packit Service aee942
		if (rv)
Packit Service aee942
		{
Packit Service aee942
			libusb_free_transfer(transfer);
Packit Service aee942
			DEBUG_COMM2("libusb_submit_transfer err %d", rv);
Packit Service aee942
			break;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		usbDevice[msExt->reader_index].polling_transfer = transfer;
Packit Service aee942
Packit Service aee942
		completed = 0;
Packit Service aee942
		while (!completed && !msExt->terminated)
Packit Service aee942
		{
Packit Service aee942
			rv = libusb_handle_events_completed(ctx, &completed);
Packit Service aee942
			if (rv < 0)
Packit Service aee942
			{
Packit Service aee942
				DEBUG_COMM2("libusb_handle_events err %d", rv);
Packit Service aee942
Packit Service aee942
				if (rv == LIBUSB_ERROR_INTERRUPTED)
Packit Service aee942
					continue;
Packit Service aee942
Packit Service aee942
				libusb_cancel_transfer(transfer);
Packit Service aee942
Packit Service aee942
				while (!completed && !msExt->terminated)
Packit Service aee942
				{
Packit Service aee942
					if (libusb_handle_events_completed(ctx, &completed) < 0)
Packit Service aee942
						break;
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
				break;
Packit Service aee942
			}
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		usbDevice[msExt->reader_index].polling_transfer = NULL;
Packit Service aee942
Packit Service aee942
		if (rv < 0)
Packit Service aee942
			libusb_free_transfer(transfer);
Packit Service aee942
		else
Packit Service aee942
		{
Packit Service aee942
			int b, slot;
Packit Service aee942
Packit Service aee942
			actual_length = transfer->actual_length;
Packit Service aee942
			status = transfer->status;
Packit Service aee942
Packit Service aee942
			libusb_free_transfer(transfer);
Packit Service aee942
Packit Service aee942
			switch (status)
Packit Service aee942
			{
Packit Service aee942
				case LIBUSB_TRANSFER_COMPLETED:
Packit Service aee942
					DEBUG_COMM3("Multi_PollingProc (%d/%d): OK",
Packit Service aee942
						usbDevice[msExt->reader_index].bus_number,
Packit Service aee942
						usbDevice[msExt->reader_index].device_address);
Packit Service aee942
					DEBUG_XXD("NotifySlotChange: ", buffer, actual_length);
Packit Service aee942
Packit Service aee942
					/* log the RDR_to_PC_NotifySlotChange data */
Packit Service aee942
					slot = 0;
Packit Service aee942
					for (b=0; b
Packit Service aee942
					{
Packit Service aee942
						int s;
Packit Service aee942
Packit Service aee942
						/* 4 slots per byte */
Packit Service aee942
						for (s=0; s<4; s++)
Packit Service aee942
						{
Packit Service aee942
							/* 2 bits per slot */
Packit Service aee942
							int slot_status = ((buffer[1+b] >> (s*2)) & 3);
Packit Service aee942
							const char *present, *change;
Packit Service aee942
Packit Service aee942
							present = (slot_status & 1) ? "present" : "absent";
Packit Service aee942
							change = (slot_status & 2) ? "status changed" : "no change";
Packit Service aee942
Packit Service aee942
							DEBUG_COMM3("slot %d status: %d",
Packit Service aee942
								s + b*4, slot_status);
Packit Service aee942
							DEBUG_COMM3("ICC %s, %s", present, change);
Packit Service aee942
						}
Packit Service aee942
						slot += 4;
Packit Service aee942
					}
Packit Service aee942
					break;
Packit Service aee942
Packit Service aee942
				case LIBUSB_TRANSFER_TIMED_OUT:
Packit Service aee942
					DEBUG_COMM3("Multi_PollingProc (%d/%d): Timeout",
Packit Service aee942
						usbDevice[msExt->reader_index].bus_number,
Packit Service aee942
						usbDevice[msExt->reader_index].device_address);
Packit Service aee942
					break;
Packit Service aee942
Packit Service aee942
				default:
Packit Service aee942
					/* if libusb_interrupt_transfer() times out
Packit Service aee942
					 * we get EILSEQ or EAGAIN */
Packit Service aee942
					DEBUG_COMM4("Multi_PollingProc (%d/%d): %d",
Packit Service aee942
						usbDevice[msExt->reader_index].bus_number,
Packit Service aee942
						usbDevice[msExt->reader_index].device_address,
Packit Service aee942
						status);
Packit Service aee942
			}
Packit Service aee942
Packit Service aee942
			/* Tell other slots that there's a new interrupt buffer */
Packit Service aee942
			DEBUG_COMM3("Multi_PollingProc (%d/%d): Broadcast to slot(s)",
Packit Service aee942
				usbDevice[msExt->reader_index].bus_number,
Packit Service aee942
				usbDevice[msExt->reader_index].device_address);
Packit Service aee942
Packit Service aee942
			/* Lock the mutex */
Packit Service aee942
			pthread_mutex_lock(&msExt->mutex);
Packit Service aee942
Packit Service aee942
			/* Set the status and the interrupt buffer */
Packit Service aee942
			msExt->status = status;
Packit Service aee942
			memset(msExt->buffer, 0, sizeof msExt->buffer);
Packit Service aee942
			memcpy(msExt->buffer, buffer, actual_length);
Packit Service aee942
Packit Service aee942
			/* Broadcast the condition and unlock */
Packit Service aee942
			pthread_cond_broadcast(&msExt->condition);
Packit Service aee942
			pthread_mutex_unlock(&msExt->mutex);
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	msExt->terminated = TRUE;
Packit Service aee942
Packit Service aee942
	if (rv < 0)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL4("Multi_PollingProc (%d/%d): error %d",
Packit Service aee942
			usbDevice[msExt->reader_index].bus_number,
Packit Service aee942
			usbDevice[msExt->reader_index].device_address, rv);
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* Wake up the slot threads so they will exit as well */
Packit Service aee942
Packit Service aee942
	/* Lock the mutex */
Packit Service aee942
	pthread_mutex_lock(&msExt->mutex);
Packit Service aee942
Packit Service aee942
	/* Set the status and fill-in the interrupt buffer */
Packit Service aee942
	msExt->status = 0;
Packit Service aee942
	memset(msExt->buffer, 0xFF, sizeof msExt->buffer);
Packit Service aee942
Packit Service aee942
	/* Broadcast the condition */
Packit Service aee942
	pthread_cond_broadcast(&msExt->condition);
Packit Service aee942
Packit Service aee942
	/* Unlock */
Packit Service aee942
	pthread_mutex_unlock(&msExt->mutex);
Packit Service aee942
Packit Service aee942
	/* Now exit */
Packit Service aee942
	DEBUG_COMM3("Multi_PollingProc (%d/%d): Thread terminated",
Packit Service aee942
		usbDevice[msExt->reader_index].bus_number,
Packit Service aee942
		usbDevice[msExt->reader_index].device_address);
Packit Service aee942
Packit Service aee942
	pthread_exit(NULL);
Packit Service aee942
	return NULL;
Packit Service aee942
} /* Multi_PollingProc */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					Multi_PollingTerminate
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static void Multi_PollingTerminate(struct usbDevice_MultiSlot_Extension *msExt)
Packit Service aee942
{
Packit Service aee942
	struct libusb_transfer *transfer;
Packit Service aee942
Packit Service aee942
	if (msExt && !msExt->terminated)
Packit Service aee942
	{
Packit Service aee942
		msExt->terminated = TRUE;
Packit Service aee942
Packit Service aee942
		transfer = usbDevice[msExt->reader_index].polling_transfer;
Packit Service aee942
Packit Service aee942
		if (transfer)
Packit Service aee942
		{
Packit Service aee942
			int ret;
Packit Service aee942
Packit Service aee942
			ret = libusb_cancel_transfer(transfer);
Packit Service aee942
			if (ret < 0)
Packit Service aee942
				DEBUG_CRITICAL2("libusb_cancel_transfer failed: %d", ret);
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
} /* Multi_PollingTerminate */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					Multi_InterruptRead
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static int Multi_InterruptRead(int reader_index, int timeout /* in ms */)
Packit Service aee942
{
Packit Service aee942
	struct usbDevice_MultiSlot_Extension *msExt;
Packit Service aee942
	unsigned char buffer[CCID_INTERRUPT_SIZE];
Packit Service aee942
	struct timespec cond_wait_until;
Packit Service aee942
	struct timeval local_time;
Packit Service aee942
	int rv, status, interrupt_byte, interrupt_mask;
Packit Service aee942
Packit Service aee942
	msExt = usbDevice[reader_index].multislot_extension;
Packit Service aee942
Packit Service aee942
	/* When stopped, return 0 so IFDHPolling will return IFD_NO_SUCH_DEVICE */
Packit Service aee942
	if ((msExt == NULL) || msExt->terminated)
Packit Service aee942
		return 0;
Packit Service aee942
Packit Service aee942
	DEBUG_PERIODIC3("Multi_InterruptRead (%d), timeout: %d ms",
Packit Service aee942
		reader_index, timeout);
Packit Service aee942
Packit Service aee942
	/* Select the relevant bit in the interrupt buffer */
Packit Service aee942
	interrupt_byte = (usbDevice[reader_index].ccid.bCurrentSlotIndex / 4) + 1;
Packit Service aee942
	interrupt_mask = 0x02 << (2 * (usbDevice[reader_index].ccid.bCurrentSlotIndex % 4));
Packit Service aee942
Packit Service aee942
	/* Wait until the condition is signaled or a timeout occurs */
Packit Service aee942
	gettimeofday(&local_time, NULL);
Packit Service aee942
	cond_wait_until.tv_sec = local_time.tv_sec;
Packit Service aee942
	cond_wait_until.tv_nsec = local_time.tv_usec * 1000;
Packit Service aee942
Packit Service aee942
	cond_wait_until.tv_sec += timeout / 1000;
Packit Service aee942
	cond_wait_until.tv_nsec += 1000000 * (timeout % 1000);
Packit Service aee942
Packit Service aee942
again:
Packit Service aee942
	pthread_mutex_lock(&msExt->mutex);
Packit Service aee942
Packit Service aee942
	rv = pthread_cond_timedwait(&msExt->condition, &msExt->mutex,
Packit Service aee942
		&cond_wait_until);
Packit Service aee942
Packit Service aee942
	if (0 == rv)
Packit Service aee942
	{
Packit Service aee942
		/* Retrieve interrupt buffer and request result */
Packit Service aee942
		memcpy(buffer, msExt->buffer, sizeof buffer);
Packit Service aee942
		status = msExt->status;
Packit Service aee942
	}
Packit Service aee942
	else
Packit Service aee942
		if (rv == ETIMEDOUT)
Packit Service aee942
			status = LIBUSB_TRANSFER_TIMED_OUT;
Packit Service aee942
		else
Packit Service aee942
			status = -1;
Packit Service aee942
Packit Service aee942
	/* Don't forget to unlock the mutex */
Packit Service aee942
	pthread_mutex_unlock(&msExt->mutex);
Packit Service aee942
Packit Service aee942
	/* When stopped, return 0 so IFDHPolling will return IFD_NO_SUCH_DEVICE */
Packit Service aee942
	if (msExt->terminated)
Packit Service aee942
		return 0;
Packit Service aee942
Packit Service aee942
	/* Not stopped */
Packit Service aee942
	if (status == LIBUSB_TRANSFER_COMPLETED)
Packit Service aee942
	{
Packit Service aee942
		if (0 == (buffer[interrupt_byte] & interrupt_mask))
Packit Service aee942
		{
Packit Service aee942
			DEBUG_PERIODIC2("Multi_InterruptRead (%d) -- skipped", reader_index);
Packit Service aee942
			goto again;
Packit Service aee942
		}
Packit Service aee942
		DEBUG_PERIODIC2("Multi_InterruptRead (%d), got an interrupt", reader_index);
Packit Service aee942
	}
Packit Service aee942
	else
Packit Service aee942
	{
Packit Service aee942
		DEBUG_PERIODIC3("Multi_InterruptRead (%d), status=%d", reader_index, status);
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return status;
Packit Service aee942
} /* Multi_InterruptRead */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					Multi_InterruptStop
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static void Multi_InterruptStop(int reader_index)
Packit Service aee942
{
Packit Service aee942
	struct usbDevice_MultiSlot_Extension *msExt;
Packit Service aee942
	int interrupt_byte, interrupt_mask;
Packit Service aee942
Packit Service aee942
	msExt = usbDevice[reader_index].multislot_extension;
Packit Service aee942
Packit Service aee942
	/* Already stopped ? */
Packit Service aee942
	if ((NULL == msExt) || msExt->terminated)
Packit Service aee942
		return;
Packit Service aee942
Packit Service aee942
	DEBUG_PERIODIC2("Stop (%d)", reader_index);
Packit Service aee942
Packit Service aee942
	interrupt_byte = (usbDevice[reader_index].ccid.bCurrentSlotIndex / 4) + 1;
Packit Service aee942
	interrupt_mask = 0x02 << (2 * (usbDevice[reader_index].ccid.bCurrentSlotIndex % 4));
Packit Service aee942
Packit Service aee942
	pthread_mutex_lock(&msExt->mutex);
Packit Service aee942
Packit Service aee942
	/* Broacast an interrupt to wake-up the slot's thread */
Packit Service aee942
	msExt->buffer[interrupt_byte] |= interrupt_mask;
Packit Service aee942
	pthread_cond_broadcast(&msExt->condition);
Packit Service aee942
Packit Service aee942
	pthread_mutex_unlock(&msExt->mutex);
Packit Service aee942
} /* Multi_InterruptStop */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					Multi_CreateFirstSlot
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static struct usbDevice_MultiSlot_Extension *Multi_CreateFirstSlot(int reader_index)
Packit Service aee942
{
Packit Service aee942
	struct usbDevice_MultiSlot_Extension *msExt;
Packit Service aee942
Packit Service aee942
	/* Allocate a new extension buffer */
Packit Service aee942
	msExt = malloc(sizeof(struct usbDevice_MultiSlot_Extension));
Packit Service aee942
	if (NULL == msExt)
Packit Service aee942
		return NULL;
Packit Service aee942
Packit Service aee942
	/* Remember the index */
Packit Service aee942
	msExt->reader_index = reader_index;
Packit Service aee942
Packit Service aee942
	msExt->terminated = FALSE;
Packit Service aee942
	msExt->status = 0;
Packit Service aee942
	msExt->transfer = NULL;
Packit Service aee942
Packit Service aee942
	/* Create mutex and condition object for the interrupt polling */
Packit Service aee942
	pthread_mutex_init(&msExt->mutex, NULL);
Packit Service aee942
	pthread_cond_init(&msExt->condition, NULL);
Packit Service aee942
Packit Service aee942
	/* create the thread in charge of the interrupt polling */
Packit Service aee942
	pthread_create(&msExt->thread_proc, NULL, Multi_PollingProc, msExt);
Packit Service aee942
Packit Service aee942
	return msExt;
Packit Service aee942
} /* Multi_CreateFirstSlot */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					Multi_CreateNextSlot
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static struct usbDevice_MultiSlot_Extension *Multi_CreateNextSlot(int physical_reader_index)
Packit Service aee942
{
Packit Service aee942
	/* Take the extension buffer from the main slot */
Packit Service aee942
	return usbDevice[physical_reader_index].multislot_extension;
Packit Service aee942
} /* Multi_CreateNextSlot */
Packit Service aee942