Esempio n. 1
0
/*****************************************************************************
 *
 *				OpenSerial: open the port
 *
 *****************************************************************************/
status_t OpenSerial(unsigned int reader_index, int channel)
{
	char dev_name[FILENAME_MAX];

	DEBUG_COMM3("Reader index: %X, Channel: %d", reader_index, channel);

	/*
	 * Conversion of old-style ifd-hanler 1.0 CHANNELID
	 */
	if (channel == 0x0103F8)
		channel = 1;
	else
		if (channel == 0x0102F8)
			channel = 2;
		else
			if (channel == 0x0103E8)
				channel = 3;
			else
				if (channel == 0x0102E8)
					channel = 4;

	if (channel < 0)
	{
		DEBUG_CRITICAL2("wrong port number: %d", channel);
		return STATUS_UNSUCCESSFUL;
	}

	(void)snprintf(dev_name, sizeof(dev_name), "/dev/pcsc/%d", channel);

	return OpenSerialByName(reader_index, dev_name);
} /* OpenSerial */
Esempio n. 2
0
/*****************************************************************************
 *
 *				get_bytes: get n bytes
 *
 *****************************************************************************/
int get_bytes(unsigned int reader_index, unsigned char *buffer, int length)
{
	int offset = serialDevice[reader_index].buffer_offset;
	int offset_last = serialDevice[reader_index].buffer_offset_last;

	DEBUG_COMM3("available: %d, needed: %d", offset_last-offset,
		length);
	/* enough data are available */
	if (offset + length <= offset_last)
	{
		DEBUG_COMM("data available");
		memcpy(buffer, serialDevice[reader_index].buffer + offset, length);
		serialDevice[reader_index].buffer_offset += length;
	}
	else
	{
		int present, rv;

		/* copy available data */
		present = offset_last - offset;

		if (present > 0)
		{
			DEBUG_COMM2("some data available: %d", present);
			memcpy(buffer, serialDevice[reader_index].buffer + offset,
				present);
		}

		/* get fresh data */
		DEBUG_COMM2("get more data: %d", length - present);
		rv = ReadChunk(reader_index, serialDevice[reader_index].buffer,
			sizeof(serialDevice[reader_index].buffer), length - present);
		if (rv < 0)
			return STATUS_COMM_ERROR;

		/* fill the buffer */
		memcpy(buffer + present, serialDevice[reader_index].buffer,
			length - present);
		serialDevice[reader_index].buffer_offset = length - present;
		serialDevice[reader_index].buffer_offset_last = rv;
		DEBUG_COMM3("offset: %d, last_offset: %d",
			serialDevice[reader_index].buffer_offset,
			serialDevice[reader_index].buffer_offset_last);
	}

	return STATUS_SUCCESS;
} /* get_bytes */
/*****************************************************************************
 *
 *					CloseUSB
 *
 ****************************************************************************/
status_t CloseUSB(unsigned int reader_index)
{
	/* device not opened */
	if (usbDevice[reader_index].handle == NULL)
		return STATUS_UNSUCCESSFUL;

	DEBUG_COMM3("Closing USB device: %s/%s",
		usbDevice[reader_index].dirname,
		usbDevice[reader_index].filename);

	if (usbDevice[reader_index].ccid.arrayOfSupportedDataRates
		&& (usbDevice[reader_index].ccid.bCurrentSlotIndex == 0))
	{
		free(usbDevice[reader_index].ccid.arrayOfSupportedDataRates);
		usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL;
	}

	/* one slot closed */
	(*usbDevice[reader_index].nb_opened_slots)--;

	/* release the allocated ressources for the last slot only */
	if (0 == *usbDevice[reader_index].nb_opened_slots)
	{
		DEBUG_COMM("Last slot closed. Release resources");

		/* reset so that bSeq starts at 0 again */
		if (DriverOptions & DRIVER_OPTION_RESET_ON_CLOSE)
			(void)usb_reset(usbDevice[reader_index].handle);

		(void)usb_release_interface(usbDevice[reader_index].handle,
			usbDevice[reader_index].interface);
		(void)usb_close(usbDevice[reader_index].handle);
#ifdef __APPLE__
		DEBUG_INFO3("Terminating thread: %s/%s",
			usbDevice[reader_index].dirname, usbDevice[reader_index].filename);

		// Terminate thread
		*usbDevice[reader_index].pTerminated = TRUE;
		pthread_join(usbDevice[reader_index].hThread, NULL);

		// Free bStatus lock
		pthread_mutex_destroy(usbDevice[reader_index].ccid.pbStatusLock);
#endif
		// Free array of bStatus
		free(usbDevice[reader_index].ccid.bStatus);

		free(usbDevice[reader_index].dirname);
		free(usbDevice[reader_index].filename);
	}

	/* mark the resource unused */
	usbDevice[reader_index].handle = NULL;
	usbDevice[reader_index].dirname = NULL;
	usbDevice[reader_index].filename = NULL;
	usbDevice[reader_index].interface = 0;
	usbDevice[reader_index].ccid.bStatus = NULL;		// Array of bStatus

	return STATUS_SUCCESS;
} /* CloseUSB */
Esempio n. 4
0
/*****************************************************************************
 *
 *					CloseUSB
 *
 ****************************************************************************/
status_t CloseUSB(unsigned int reader_index)
{
	/* device not opened */
	if (usbDevice[reader_index].dev_handle == NULL)
		return STATUS_UNSUCCESSFUL;

	DEBUG_COMM3("Closing USB device: %d/%d",
		usbDevice[reader_index].bus_number,
		usbDevice[reader_index].device_address);

	if (usbDevice[reader_index].ccid.arrayOfSupportedDataRates
		&& (usbDevice[reader_index].ccid.bCurrentSlotIndex == 0))
	{
		free(usbDevice[reader_index].ccid.arrayOfSupportedDataRates);
		usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL;
	}

	if (usbDevice[reader_index].ccid.gemalto_firmware_features)
	{
		free(usbDevice[reader_index].ccid.gemalto_firmware_features);
		usbDevice[reader_index].ccid.gemalto_firmware_features = NULL ;
	}

	/* one slot closed */
	(*usbDevice[reader_index].nb_opened_slots)--;

	/* release the allocated ressources for the last slot only */
	if (0 == *usbDevice[reader_index].nb_opened_slots)
	{
		DEBUG_COMM("Last slot closed. Release resources");

		if (usbDevice[reader_index].ccid.sIFD_serial_number)
			free(usbDevice[reader_index].ccid.sIFD_serial_number);

		if (usbDevice[reader_index].ccid.sIFD_iManufacturer)
			free(usbDevice[reader_index].ccid.sIFD_iManufacturer);

		/* reset so that bSeq starts at 0 again */
		if (DriverOptions & DRIVER_OPTION_RESET_ON_CLOSE)
			(void)libusb_reset_device(usbDevice[reader_index].dev_handle);

		(void)libusb_release_interface(usbDevice[reader_index].dev_handle,
			usbDevice[reader_index].interface);
		(void)libusb_close(usbDevice[reader_index].dev_handle);

		/* does not work for libusb <= 1.0.8 */
		/* libusb_exit(ctx); */
	}

	/* mark the resource unused */
	usbDevice[reader_index].dev_handle = NULL;
	usbDevice[reader_index].interface = 0;

	return STATUS_SUCCESS;
} /* CloseUSB */
Esempio n. 5
0
/*****************************************************************************
 *
 *				ReadChunk: read a minimum number of bytes
 *
 *****************************************************************************/
static int ReadChunk(unsigned int reader_index, unsigned char *buffer,
	int buffer_length, int min_length)
{
	int fd = serialDevice[reader_index].fd;
# ifndef S_SPLINT_S
	fd_set fdset;
# endif
	struct timeval t;
	int i, rv = 0;
	int already_read;
	char debug_header[] = "<- 123456 ";

	(void)snprintf(debug_header, sizeof(debug_header), "<- %06X ",
		reader_index);

	already_read = 0;
	while (already_read < min_length)
	{
		/* use select() to, eventually, timeout */
		FD_ZERO(&fdset);
		FD_SET(fd, &fdset);
		t.tv_sec = serialDevice[reader_index].ccid.readTimeout / 1000;
		t.tv_usec = (serialDevice[reader_index].ccid.readTimeout - t.tv_sec*1000)*1000;

		i = select(fd+1, &fdset, NULL, NULL, &t);
		if (i == -1)
		{
			DEBUG_CRITICAL2("select: %s", strerror(errno));
			return -1;
		}
		else
			if (i == 0)
			{
				DEBUG_COMM2("Timeout! (%d ms)", serialDevice[reader_index].ccid.readTimeout);
				return -1;
			}

		rv = read(fd, buffer + already_read, buffer_length - already_read);
		if (rv < 0)
		{
			DEBUG_COMM2("read error: %s", strerror(errno));
			return -1;
		}

		DEBUG_XXD(debug_header, buffer + already_read, rv);

		already_read += rv;
		DEBUG_COMM3("read: %d, to read: %d", already_read,
			min_length);
	}

	return already_read;
} /* ReadChunk */
Esempio n. 6
0
/*****************************************************************************
 *
 *					CloseUSB
 *
 ****************************************************************************/
status_t CloseUSB(unsigned int reader_index)
{
	/* device not opened */
	if (usbDevice[reader_index].handle == NULL)
		return STATUS_UNSUCCESSFUL;

	DEBUG_COMM3("Closing USB device: %s/%s",
		usbDevice[reader_index].dirname,
		usbDevice[reader_index].filename);

	if (usbDevice[reader_index].ccid.arrayOfSupportedDataRates
		&& (usbDevice[reader_index].ccid.bCurrentSlotIndex == 0))
	{
		free(usbDevice[reader_index].ccid.arrayOfSupportedDataRates);
		usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL;
	}

	/* one slot closed */
	(*usbDevice[reader_index].nb_opened_slots)--;

	/* release the allocated ressources for the last slot only */
	if (0 == *usbDevice[reader_index].nb_opened_slots)
	{
		DEBUG_COMM("Last slot closed. Release resources");

		/* reset so that bSeq starts at 0 again */
		if (DriverOptions & DRIVER_OPTION_RESET_ON_CLOSE)
			(void)usb_reset(usbDevice[reader_index].handle);

		(void)usb_release_interface(usbDevice[reader_index].handle,
			usbDevice[reader_index].interface);
		(void)usb_close(usbDevice[reader_index].handle);

		free(usbDevice[reader_index].dirname);
		free(usbDevice[reader_index].filename);
	}

	/* mark the resource unused */
	usbDevice[reader_index].handle = NULL;
	usbDevice[reader_index].dirname = NULL;
	usbDevice[reader_index].filename = NULL;
	usbDevice[reader_index].interface = 0;

	return STATUS_SUCCESS;
} /* CloseUSB */
Esempio n. 7
0
/*****************************************************************************
 *
 *					OpenUSBByName
 *
 ****************************************************************************/
status_t OpenUSBByName(unsigned int reader_index, /*@null@*/ char *device)
{
	unsigned int alias;
	struct libusb_device_handle *dev_handle;
	char infofile[FILENAME_MAX];
#ifndef __APPLE__
	unsigned int device_vendor, device_product;
#endif
	int interface_number = -1;
	int i;
	static int previous_reader_index = -1;
	libusb_device **devs, *dev;
	ssize_t cnt;
	list_t plist, *values, *ifdVendorID, *ifdProductID, *ifdFriendlyName;
	int rv;
	int claim_failed = FALSE;
	int return_value = STATUS_SUCCESS;

	DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, device);

#ifndef __APPLE__
	/* device name specified */
	if (device)
	{
		char *dirname;

		/* format: usb:%04x/%04x, vendor, product */
		if (strncmp("usb:", device, 4) != 0)
		{
			DEBUG_CRITICAL2("device name does not start with \"usb:\": %s",
				device);
			return STATUS_UNSUCCESSFUL;
		}

		if (sscanf(device, "usb:%x/%x", &device_vendor, &device_product) != 2)
		{
			DEBUG_CRITICAL2("device name can't be parsed: %s", device);
			return STATUS_UNSUCCESSFUL;
		}

		/* format usb:%04x/%04x:libudev:%d:%s
		 * with %d set to
		 * 01 (or whatever the interface number is)
		 * and %s set to
		 * /dev/bus/usb/008/004
		 */
		if ((dirname = strstr(device, "libudev:")) != NULL)
		{
			/* convert the interface number */
			interface_number = atoi(dirname + 8 /* "libudev:" */);
			DEBUG_COMM2("interface_number: %d", interface_number);
		}
	}
#endif

	/* is the reader_index already used? */
	if (usbDevice[reader_index].dev_handle != NULL)
	{
		DEBUG_CRITICAL2("USB driver with index %X already in use",
			reader_index);
		return STATUS_UNSUCCESSFUL;
	}

	/* Info.plist full patch filename */
	(void)snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist",
		PCSCLITE_HP_DROPDIR, BUNDLE);
	DEBUG_INFO2("Using: %s", infofile);

	rv = bundleParse(infofile, &plist);
	if (rv)
		return STATUS_UNSUCCESSFUL;

#define GET_KEY(key, values) \
	rv = LTPBundleFindValueWithKey(&plist, key, &values); \
	if (rv) \
	{ \
		DEBUG_CRITICAL2("Value/Key not defined for " key " in %s", infofile); \
		return_value = STATUS_UNSUCCESSFUL; \
		goto end1; \
	} \
	else \
		DEBUG_INFO2(key ": %s", (char *)list_get_at(values, 0));

	/* general driver info */
	GET_KEY("ifdManufacturerString", values)
	GET_KEY("ifdProductString", values)
	GET_KEY("Copyright", values)

	if (NULL == ctx)
	{
		rv = libusb_init(&ctx);
		if (rv != 0)
		{
			DEBUG_CRITICAL2("libusb_init failed: %d", rv);
			return_value = STATUS_UNSUCCESSFUL;
			goto end1;
		}
	}

	cnt = libusb_get_device_list(ctx, &devs);
	if (cnt < 0)
	{
		DEBUG_CRITICAL("libusb_get_device_list() failed\n");
		return_value = STATUS_UNSUCCESSFUL;
		goto end1;
	}

#define GET_KEYS(key, values) \
	rv = LTPBundleFindValueWithKey(&plist, key, values); \
	if (rv) \
	{ \
		DEBUG_CRITICAL2("Value/Key not defined for " key " in %s", infofile); \
		return_value = STATUS_UNSUCCESSFUL; \
		goto end2; \
	}

	GET_KEYS("ifdVendorID", &ifdVendorID)
	GET_KEYS("ifdProductID", &ifdProductID);
	GET_KEYS("ifdFriendlyName", &ifdFriendlyName)

	/* The 3 lists do not have the same size */
	if  ((list_size(ifdVendorID) != list_size(ifdProductID))
		|| (list_size(ifdVendorID) != list_size(ifdFriendlyName)))
	{
		DEBUG_CRITICAL2("Error parsing %s", infofile);
		return_value = STATUS_UNSUCCESSFUL;
		goto end1;
	}

	/* for any supported reader */
	for (alias=0; alias<list_size(ifdVendorID); alias++)
	{
		unsigned int vendorID, productID;
		char *friendlyName;

		vendorID = strtoul(list_get_at(ifdVendorID, alias), NULL, 0);
		productID = strtoul(list_get_at(ifdProductID, alias), NULL, 0);
		friendlyName = list_get_at(ifdFriendlyName, alias);

#ifndef __APPLE__
		/* the device was specified but is not the one we are trying to find */
		if (device
			&& (vendorID != device_vendor || productID != device_product))
			continue;
#else
		/* Leopard puts the friendlyname in the device argument */
		if (device && strcmp(device, friendlyName))
			continue;
#endif

		/* for every device */
		i = 0;
		while ((dev = devs[i++]) != 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);

			int r = libusb_get_device_descriptor(dev, &desc);
			if (r < 0)
			{
				DEBUG_INFO3("failed to get device descriptor for %d/%d",
					bus_number, device_address);
				continue;
			}

			if (desc.idVendor == vendorID && desc.idProduct == productID)
			{
				int already_used;
				const struct libusb_interface *usb_interface = NULL;
				int interface;
				int num = 0;
				const unsigned char *device_descriptor;
#if defined(USE_COMPOSITE_AS_MULTISLOT) || defined(__APPLE__)
				int readerID = (vendorID << 16) + productID;
#endif

#ifdef USE_COMPOSITE_AS_MULTISLOT
				static int static_interface = 1;

				/* simulate a composite device as when libudev is used */
				if ((GEMALTOPROXDU == readerID)
					|| (GEMALTOPROXSU == readerID))
				{
						/*
						 * We can't talk to the two CCID interfaces
						 * at the same time (the reader enters a
						 * dead lock). So we simulate a multi slot
						 * reader. By default multi slot readers
						 * can't use the slots at the same time. See
						 * TAG_IFD_SLOT_THREAD_SAFE
						 *
						 * One side effect is that the two readers
						 * are seen by pcscd as one reader so the
						 * interface name is the same for the two.
						 *
	* So we have:
	* 0: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 00
	* 1: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 01
	* instead of
	* 0: Gemalto Prox-DU [Prox-DU Contact_09A00795] (09A00795) 00 00
	* 1: Gemalto Prox-DU [Prox-DU Contactless_09A00795] (09A00795) 01 00
						 */

					/* the CCID interfaces are 1 and 2 */
					interface_number = static_interface;
				}
#endif
				/* is it already opened? */
				already_used = FALSE;

				DEBUG_COMM3("Checking device: %d/%d",
					bus_number, device_address);
				for (r=0; r<CCID_DRIVER_MAX_READERS; r++)
				{
					if (usbDevice[r].dev_handle)
					{
						/* same bus, same address */
						if (usbDevice[r].bus_number == bus_number
							&& usbDevice[r].device_address == device_address)
							already_used = TRUE;
					}
				}

				/* this reader is already managed by us */
				if (already_used)
				{
					if ((previous_reader_index != -1)
						&& usbDevice[previous_reader_index].dev_handle
						&& (usbDevice[previous_reader_index].bus_number == bus_number)
						&& (usbDevice[previous_reader_index].device_address == device_address)
						&& usbDevice[previous_reader_index].ccid.bCurrentSlotIndex < usbDevice[previous_reader_index].ccid.bMaxSlotIndex)
					{
						/* we reuse the same device
						 * and the reader is multi-slot */
						usbDevice[reader_index] = usbDevice[previous_reader_index];
						/* the other slots do not have the same data rates */
						if ((GEMCOREPOSPRO == usbDevice[reader_index].ccid.readerID)
							|| (GEMCORESIMPRO == usbDevice[reader_index].ccid.readerID))
						{
							usbDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialCustomDataRates;
							usbDevice[reader_index].ccid.dwMaxDataRate = 125000;
						}

						*usbDevice[reader_index].nb_opened_slots += 1;
						usbDevice[reader_index].ccid.bCurrentSlotIndex++;
						usbDevice[reader_index].ccid.dwSlotStatus =
							IFD_ICC_PRESENT;
						DEBUG_INFO2("Opening slot: %d",
							usbDevice[reader_index].ccid.bCurrentSlotIndex);
						goto end;
					}
					else
					{
						/* if an interface number is given by HAL we
						 * continue with this device. */
						if (-1 == interface_number)
						{
							DEBUG_INFO3("USB device %d/%d already in use."
								" Checking next one.",
								bus_number, device_address);
							continue;
						}
					}
				}

				DEBUG_COMM3("Trying to open USB bus/device: %d/%d",
					bus_number, device_address);

				r = libusb_open(dev, &dev_handle);
				if (r < 0)
				{
					DEBUG_CRITICAL4("Can't libusb_open(%d/%d): %d",
						bus_number, device_address, r);

					continue;
				}

again:
#ifdef __APPLE__
				/* Some early Gemalto Ezio CB+ readers have
				 * bDeviceClass, bDeviceSubClass and bDeviceProtocol set
				 * to 0xFF (proprietary) instead of 0x00.
				 *
				 * So on Mac OS X the reader configuration is not done
				 * by the OS/kernel and we do it ourself.
				 */
				if (GEMALTO_EZIO_CBP == readerID)
				{
					r = libusb_set_configuration(dev_handle, 1);
					if (r < 0)
					{
						(void)libusb_close(dev_handle);
						DEBUG_CRITICAL4("Can't set configuration on %d/%d: %d",
							bus_number, device_address, r);
						continue;
					}
				}
#endif

				r = libusb_get_active_config_descriptor(dev, &config_desc);
				if (r < 0)
				{
					(void)libusb_close(dev_handle);
					DEBUG_CRITICAL4("Can't get config descriptor on %d/%d: %d",
						bus_number, device_address, r);
					continue;
				}

				usb_interface = get_ccid_usb_interface(config_desc, &num);
				if (usb_interface == NULL)
				{
					(void)libusb_close(dev_handle);
					if (0 == num)
						DEBUG_CRITICAL3("Can't find a CCID interface on %d/%d",
							bus_number, device_address);
					interface_number = -1;
					continue;
				}

				device_descriptor = get_ccid_device_descriptor(usb_interface);
				if (NULL == device_descriptor)
				{
					(void)libusb_close(dev_handle);
					DEBUG_CRITICAL3("Unable to find the device descriptor for %d/%d",
						bus_number, device_address);
					return_value = STATUS_UNSUCCESSFUL;
					goto end2;
				}

				interface = usb_interface->altsetting->bInterfaceNumber;
				if (interface_number >= 0 && interface != interface_number)
				{
					/* an interface was specified and it is not the
					 * current one */
					DEBUG_INFO3("Found interface %d but expecting %d",
						interface_number, interface);
					DEBUG_INFO3("Wrong interface for USB device %d/%d."
						" Checking next one.", bus_number, device_address);

					/* check for another CCID interface on the same device */
					num++;

					goto again;
				}

				r = libusb_claim_interface(dev_handle, interface);
				if (r < 0)
				{
					(void)libusb_close(dev_handle);
					DEBUG_CRITICAL4("Can't claim interface %d/%d: %d",
						bus_number, device_address, r);
					claim_failed = TRUE;
					interface_number = -1;
					continue;
				}

				DEBUG_INFO4("Found Vendor/Product: %04X/%04X (%s)",
					desc.idVendor, desc.idProduct, friendlyName);
				DEBUG_INFO3("Using USB bus/device: %d/%d",
					bus_number, device_address);

				/* check for firmware bugs */
				if (ccid_check_firmware(&desc))
				{
					(void)libusb_close(dev_handle);
					return_value = STATUS_UNSUCCESSFUL;
					goto end2;
				}

#ifdef USE_COMPOSITE_AS_MULTISLOT
				/* use the next interface for the next "slot" */
				static_interface++;

				/* reset for a next reader */
				if (static_interface > 2)
					static_interface = 1;
#endif

				/* Get Endpoints values*/
				(void)get_end_points(config_desc, &usbDevice[reader_index], num);

				/* store device information */
				usbDevice[reader_index].dev_handle = dev_handle;
				usbDevice[reader_index].bus_number = bus_number;
				usbDevice[reader_index].device_address = device_address;
				usbDevice[reader_index].interface = interface;
				usbDevice[reader_index].real_nb_opened_slots = 1;
				usbDevice[reader_index].nb_opened_slots = &usbDevice[reader_index].real_nb_opened_slots;
				usbDevice[reader_index].polling_transfer = NULL;

				/* CCID common informations */
				usbDevice[reader_index].ccid.real_bSeq = 0;
				usbDevice[reader_index].ccid.pbSeq = &usbDevice[reader_index].ccid.real_bSeq;
				usbDevice[reader_index].ccid.readerID =
					(desc.idVendor << 16) + desc.idProduct;
				usbDevice[reader_index].ccid.dwFeatures = dw2i(device_descriptor, 40);
				usbDevice[reader_index].ccid.wLcdLayout =
					(device_descriptor[51] << 8) + device_descriptor[50];
				usbDevice[reader_index].ccid.bPINSupport = device_descriptor[52];
				usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = dw2i(device_descriptor, 44);
				usbDevice[reader_index].ccid.dwMaxIFSD = dw2i(device_descriptor, 28);
				usbDevice[reader_index].ccid.dwDefaultClock = dw2i(device_descriptor, 10);
				usbDevice[reader_index].ccid.dwMaxDataRate = dw2i(device_descriptor, 23);
				usbDevice[reader_index].ccid.bMaxSlotIndex = device_descriptor[4];
				usbDevice[reader_index].ccid.bCurrentSlotIndex = 0;
				usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT;
				usbDevice[reader_index].ccid.arrayOfSupportedDataRates = get_data_rates(reader_index, config_desc, num);
				usbDevice[reader_index].ccid.bInterfaceProtocol = usb_interface->altsetting->bInterfaceProtocol;
				usbDevice[reader_index].ccid.bNumEndpoints = usb_interface->altsetting->bNumEndpoints;
				usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT;
				usbDevice[reader_index].ccid.bVoltageSupport = device_descriptor[5];
				usbDevice[reader_index].ccid.sIFD_serial_number = NULL;
				usbDevice[reader_index].ccid.gemalto_firmware_features = NULL;
				if (desc.iSerialNumber)
				{
					unsigned char serial[128];
					int ret;

					ret = libusb_get_string_descriptor_ascii(dev_handle,
							desc.iSerialNumber, serial,
							sizeof(serial));
					if (ret > 0)
						usbDevice[reader_index].ccid.sIFD_serial_number
							= strdup((char *)serial);
				}

				usbDevice[reader_index].ccid.sIFD_iManufacturer = NULL;
				if (desc.iManufacturer)
				{
					unsigned char iManufacturer[128];
					int ret;

					ret = libusb_get_string_descriptor_ascii(dev_handle,
							desc.iManufacturer, iManufacturer,
							sizeof(iManufacturer));
					if (ret > 0)
						usbDevice[reader_index].ccid.sIFD_iManufacturer
							= strdup((char *)iManufacturer);
				}

				usbDevice[reader_index].ccid.IFD_bcdDevice = desc.bcdDevice;
				goto end;
			}
		}
	}
end:
	if (usbDevice[reader_index].dev_handle == NULL)
	{
		/* does not work for libusb <= 1.0.8 */
		/* libusb_exit(ctx); */
		if (claim_failed)
			return STATUS_COMM_ERROR;
		return STATUS_NO_SUCH_DEVICE;
	}

	/* memorise the current reader_index so we can detect
	 * a new OpenUSBByName on a multi slot reader */
	previous_reader_index = reader_index;

end2:
	/* free the libusb allocated list & devices */
	libusb_free_device_list(devs, 1);

end1:
	/* free bundle list */
	bundleRelease(&plist);

	return return_value;
} /* OpenUSBByName */
Esempio n. 8
0
/*****************************************************************************
 *
 *					OpenUSBByName
 *
 ****************************************************************************/
status_t OpenUSBByName(unsigned int reader_index, /*@null@*/ char *device)
{
	static struct usb_bus *busses = NULL;
	int alias = 0;
	struct usb_bus *bus;
	struct usb_dev_handle *dev_handle;
	char keyValue[TOKEN_MAX_VALUE_SIZE];
	unsigned int vendorID, productID;
	char infofile[FILENAME_MAX];
#ifndef __APPLE__
	unsigned int device_vendor, device_product;
#endif
	char *dirname = NULL, *filename = NULL;
	int interface_number = -1;
	static int previous_reader_index = -1;

	DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, device);

#ifndef __APPLE__
	/* device name specified */
	if (device)
	{
		/* format: usb:%04x/%04x, vendor, product */
		if (strncmp("usb:", device, 4) != 0)
		{
			DEBUG_CRITICAL2("device name does not start with \"usb:\": %s",
				device);
			return STATUS_UNSUCCESSFUL;
		}

		if (sscanf(device, "usb:%x/%x", &device_vendor, &device_product) != 2)
		{
			DEBUG_CRITICAL2("device name can't be parsed: %s", device);
			return STATUS_UNSUCCESSFUL;
		}

		/* format usb:%04x/%04x:libusb:%s
		 * with %s set to %s:%s, dirname, filename */
		if ((dirname = strstr(device, "libusb:")) != NULL)
		{
			/* dirname points to the first char after libusb: */
			dirname += strlen("libusb:");

			/* search the : (separation) char */
			filename = strchr(dirname, ':');

			if (filename)
			{
				/* end the dirname string */
				*filename = '\0';

				/* filename points to the first char after : */
				filename++;
			}
			else
			{
				/* parse failed */
				dirname = NULL;

				DEBUG_CRITICAL2("can't parse using libusb scheme: %s", device);
			}
		}

		/* format usb:%04x/%04x:libhal:%s
		 * with %s set to
		 * /org/freedesktop/Hal/devices/usb_device_VID_PID_SERIAL_ifX
		 * VID is VendorID
		 * PID is ProductID
		 * SERIAL is device serial number
		 * X is the interface number
		 */
		if ((dirname = strstr(device, "libhal:")) != NULL)
		{
			const char *p;

#define HAL_HEADER "usb_device_"

			/* parse the hal string */
			if (
				/* search the last '/' char */
				(p = strrchr(dirname, '/'))

				/* if the string starts with "usb_device_" we continue */
				&& (0 == strncmp(++p, HAL_HEADER, sizeof(HAL_HEADER)-1))
				/* skip the HAL header */
				&& (p += sizeof(HAL_HEADER)-1)

				/* search the last '_' */
				&& (p = strrchr(++p, '_'))
				&& (0 == strncmp(++p, "if", 2))
			   )
			{
				/* convert the interface number */
				interface_number = atoi(p+2);
			}
			else
				DEBUG_CRITICAL2("can't parse using libhal scheme: %s", device);

			/* dirname was just a temporary variable */
			dirname = NULL;
		}
	}
#endif

	if (busses == NULL)
		usb_init();

	(void)usb_find_busses();
	(void)usb_find_devices();

	busses = usb_get_busses();

	if (busses == NULL)
	{
		DEBUG_CRITICAL("No USB busses found");
		return STATUS_UNSUCCESSFUL;
	}

	/* is the reader_index already used? */
	if (usbDevice[reader_index].handle != NULL)
	{
		DEBUG_CRITICAL2("USB driver with index %X already in use",
			reader_index);
		return STATUS_UNSUCCESSFUL;
	}

	/* Info.plist full patch filename */
	(void)snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist",
		PCSCLITE_HP_DROPDIR, BUNDLE);

	/* general driver info */
	if (!LTPBundleFindValueWithKey(infofile, "ifdManufacturerString", keyValue, 0))
	{
		DEBUG_INFO2("Manufacturer: %s", keyValue);
	}
	else
	{
		DEBUG_INFO2("LTPBundleFindValueWithKey error. Can't find %s?",
			infofile);
		return STATUS_UNSUCCESSFUL;
	}
	if (!LTPBundleFindValueWithKey(infofile, "ifdProductString", keyValue, 0))
	{
		DEBUG_INFO2("ProductString: %s", keyValue);
	}
	else
		return STATUS_UNSUCCESSFUL;
	if (!LTPBundleFindValueWithKey(infofile, "Copyright", keyValue, 0))
	{
		DEBUG_INFO2("Copyright: %s", keyValue);
	}
	else
		return STATUS_UNSUCCESSFUL;
	vendorID = strlen(keyValue);
	alias = 0x1C;
	for (; vendorID--;)
		alias ^= keyValue[vendorID];

	/* for any supported reader */
	while (LTPBundleFindValueWithKey(infofile, PCSCLITE_MANUKEY_NAME, keyValue, alias) == 0)
	{
		vendorID = strtoul(keyValue, NULL, 0);

		if (LTPBundleFindValueWithKey(infofile, PCSCLITE_PRODKEY_NAME, keyValue, alias))
			goto end;
		productID = strtoul(keyValue, NULL, 0);

		if (LTPBundleFindValueWithKey(infofile, PCSCLITE_NAMEKEY_NAME, keyValue, alias))
			goto end;

		/* go to next supported reader for next round */
		alias++;

#ifndef __APPLE__
		/* the device was specified but is not the one we are trying to find */
		if (device
			&& (vendorID != device_vendor || productID != device_product))
			continue;
#else
		/* Leopard puts the friendlyname in the device argument */
		if (device && strcmp(device, keyValue))
			continue;
#endif

		/* on any USB buses */
		for (bus = busses; bus; bus = bus->next)
		{
			struct usb_device *dev;

			/* any device on this bus */
			for (dev = bus->devices; dev; dev = dev->next)
			{
				/* device defined by name? */
				if (dirname && (strcmp(dirname, bus->dirname)
					|| strcmp(filename, dev->filename)))
					continue;

				if (dev->descriptor.idVendor == vendorID
					&& dev->descriptor.idProduct == productID)
				{
					int r, already_used;
					struct usb_interface *usb_interface = NULL;
					int interface;
					int num = 0;

#ifdef USE_COMPOSITE_AS_MULTISLOT
					static int static_interface = 1;

					{
						/* simulate a composite device as when libhal is
						 * used */
						int readerID = (vendorID << 16) + productID;

						if ((GEMALTOPROXDU == readerID)
							|| (GEMALTOPROXSU == readerID))
						{
							if(interface_number >= 0)
							{
								DEBUG_CRITICAL("USE_COMPOSITE_AS_MULTISLOT can't be used with libhal");
								continue;
							}

							/* the CCID interfaces are 1 and 2 */
							interface_number = static_interface;
						}
					}
#endif
					/* is it already opened? */
					already_used = FALSE;

					DEBUG_COMM3("Checking device: %s/%s",
						bus->dirname, dev->filename);
					for (r=0; r<CCID_DRIVER_MAX_READERS; r++)
					{
						if (usbDevice[r].handle)
						{
							/* same busname, same filename */
							if (strcmp(usbDevice[r].dirname, bus->dirname) == 0 && strcmp(usbDevice[r].filename, dev->filename) == 0)
								already_used = TRUE;
						}
					}

					/* this reader is already managed by us */
					if (already_used)
					{
						if ((previous_reader_index != -1)
							&& usbDevice[previous_reader_index].handle
							&& (strcmp(usbDevice[previous_reader_index].dirname, bus->dirname)  == 0)
							&& (strcmp(usbDevice[previous_reader_index].filename, dev->filename) == 0)
							&& usbDevice[previous_reader_index].ccid.bCurrentSlotIndex < usbDevice[previous_reader_index].ccid.bMaxSlotIndex)
						{
							/* we reuse the same device
							 * and the reader is multi-slot */
							usbDevice[reader_index] = usbDevice[previous_reader_index];
							/* the other slots do not have the same data rates */
							if ((GEMCOREPOSPRO == usbDevice[reader_index].ccid.readerID)
								|| (GEMCORESIMPRO == usbDevice[reader_index].ccid.readerID))
							{
								usbDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialCustomDataRates;
								usbDevice[reader_index].ccid.dwMaxDataRate = 125000;
							}

							*usbDevice[reader_index].nb_opened_slots += 1;
							usbDevice[reader_index].ccid.bCurrentSlotIndex++;
							usbDevice[reader_index].ccid.dwSlotStatus =
								IFD_ICC_PRESENT;
							DEBUG_INFO2("Opening slot: %d",
								usbDevice[reader_index].ccid.bCurrentSlotIndex);
							goto end;
						}
						else
						{
							/* if an interface number is given by HAL we
							 * continue with this device. */
							if (-1 == interface_number)
							{
								DEBUG_INFO3("USB device %s/%s already in use."
									" Checking next one.",
									bus->dirname, dev->filename);
								continue;
							}
						}
					}

					DEBUG_COMM3("Trying to open USB bus/device: %s/%s",
						 bus->dirname, dev->filename);

					dev_handle = usb_open(dev);
					if (dev_handle == NULL)
					{
						DEBUG_CRITICAL4("Can't usb_open(%s/%s): %s",
							bus->dirname, dev->filename, strerror(errno));

						continue;
					}

					/* now we found a free reader and we try to use it */
					if (dev->config == NULL)
					{
						(void)usb_close(dev_handle);
						DEBUG_CRITICAL3("No dev->config found for %s/%s",
							 bus->dirname, dev->filename);
						return STATUS_UNSUCCESSFUL;
					}

again:
					usb_interface = get_ccid_usb_interface(dev, &num);
					if (usb_interface == NULL)
					{
						(void)usb_close(dev_handle);
						if (0 == num)
							DEBUG_CRITICAL3("Can't find a CCID interface on %s/%s",
								bus->dirname, dev->filename);
						interface_number = -1;
						continue;
					}

					if (usb_interface->altsetting->extralen != 54)
					{
						(void)usb_close(dev_handle);
						DEBUG_CRITICAL4("Extra field for %s/%s has a wrong length: %d", bus->dirname, dev->filename, usb_interface->altsetting->extralen);
						return STATUS_UNSUCCESSFUL;
					}

					interface = usb_interface->altsetting->bInterfaceNumber;
					if (interface_number >= 0 && interface != interface_number)
					{
						/* an interface was specified and it is not the
						 * current one */
						DEBUG_INFO3("Wrong interface for USB device %s/%s."
							" Checking next one.", bus->dirname, dev->filename);

						/* check for another CCID interface on the same device */
						num++;

						goto again;
					}

					if (usb_claim_interface(dev_handle, interface) < 0)
					{
						(void)usb_close(dev_handle);
						DEBUG_CRITICAL4("Can't claim interface %s/%s: %s",
							bus->dirname, dev->filename, strerror(errno));
						interface_number = -1;
						continue;
					}

					DEBUG_INFO4("Found Vendor/Product: %04X/%04X (%s)",
						dev->descriptor.idVendor,
						dev->descriptor.idProduct, keyValue);
					DEBUG_INFO3("Using USB bus/device: %s/%s",
						 bus->dirname, dev->filename);

					/* check for firmware bugs */
					if (ccid_check_firmware(dev))
					{
						(void)usb_close(dev_handle);
						return STATUS_UNSUCCESSFUL;
					}

#ifdef USE_COMPOSITE_AS_MULTISLOT
					/* use the next interface for the next "slot" */
					static_interface++;

					/* reset for a next reader */
					if (static_interface > 2)
						static_interface = 1;
#endif

					/* Get Endpoints values*/
					(void)get_end_points(dev, &usbDevice[reader_index], num);

					/* store device information */
					usbDevice[reader_index].handle = dev_handle;
					usbDevice[reader_index].dirname = strdup(bus->dirname);
					usbDevice[reader_index].filename = strdup(dev->filename);
					usbDevice[reader_index].interface = interface;
					usbDevice[reader_index].real_nb_opened_slots = 1;
					usbDevice[reader_index].nb_opened_slots = &usbDevice[reader_index].real_nb_opened_slots;

					/* CCID common informations */
					usbDevice[reader_index].ccid.real_bSeq = 0;
					usbDevice[reader_index].ccid.pbSeq = &usbDevice[reader_index].ccid.real_bSeq;
					usbDevice[reader_index].ccid.readerID =
						(dev->descriptor.idVendor << 16) +
						dev->descriptor.idProduct;
					usbDevice[reader_index].ccid.dwFeatures = dw2i(usb_interface->altsetting->extra, 40);
					usbDevice[reader_index].ccid.wLcdLayout =
						(usb_interface->altsetting->extra[51] << 8) +
						usb_interface->altsetting->extra[50];
					usbDevice[reader_index].ccid.bPINSupport = usb_interface->altsetting->extra[52];
					usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = dw2i(usb_interface->altsetting->extra, 44);
					usbDevice[reader_index].ccid.dwMaxIFSD = dw2i(usb_interface->altsetting->extra, 28);
					usbDevice[reader_index].ccid.dwDefaultClock = dw2i(usb_interface->altsetting->extra, 10);
					usbDevice[reader_index].ccid.dwMaxDataRate = dw2i(usb_interface->altsetting->extra, 23);
					usbDevice[reader_index].ccid.bMaxSlotIndex = usb_interface->altsetting->extra[4];
					usbDevice[reader_index].ccid.bCurrentSlotIndex = 0;
					usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT;
					usbDevice[reader_index].ccid.arrayOfSupportedDataRates = get_data_rates(reader_index, dev, num);
					usbDevice[reader_index].ccid.bInterfaceProtocol = usb_interface->altsetting->bInterfaceProtocol;
					usbDevice[reader_index].ccid.bNumEndpoints = usb_interface->altsetting->bNumEndpoints;
					usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT;
					usbDevice[reader_index].ccid.bVoltageSupport = usb_interface->altsetting->extra[5];
					goto end;
				}
			}
		}
	}
end:
	if (usbDevice[reader_index].handle == NULL)
		return STATUS_NO_SUCH_DEVICE;

	/* memorise the current reader_index so we can detect
	 * a new OpenUSBByName on a multi slot reader */
	previous_reader_index = reader_index;

	return STATUS_SUCCESS;
} /* OpenUSBByName */
Esempio n. 9
0
/*****************************************************************************
 *
 *					CloseUSB
 *
 ****************************************************************************/
status_t CloseUSB(unsigned int reader_index)
{
	/* device not opened */
	if (usbDevice[reader_index].dev_handle == NULL)
		return STATUS_UNSUCCESSFUL;

	DEBUG_COMM3("Closing USB device: %d/%d",
		usbDevice[reader_index].bus_number,
		usbDevice[reader_index].device_address);

	/* one slot closed */
	(*usbDevice[reader_index].nb_opened_slots)--;

	/* release the allocated ressources for the last slot only */
	if (0 == *usbDevice[reader_index].nb_opened_slots)
	{
		struct usbDevice_MultiSlot_Extension *msExt;

		DEBUG_COMM("Last slot closed. Release resources");

		msExt = usbDevice[reader_index].multislot_extension;
		/* If this is a multislot reader, close using the multislot stuff */
		if (msExt)
		{
			/* terminate the interrupt waiter thread */
			Multi_PollingTerminate(msExt);

			/* wait for the thread to actually terminate */
			pthread_join(msExt->thread_proc, NULL);

			/* release the shared objects */
			pthread_cond_destroy(&msExt->condition);
			pthread_mutex_destroy(&msExt->mutex);

			/* Deallocate the extension itself */
			free(msExt);

			/* Stop the slot */
			usbDevice[reader_index].multislot_extension = NULL;
		}

		if (usbDevice[reader_index].ccid.gemalto_firmware_features)
			free(usbDevice[reader_index].ccid.gemalto_firmware_features);

		if (usbDevice[reader_index].ccid.sIFD_serial_number)
			free(usbDevice[reader_index].ccid.sIFD_serial_number);

		if (usbDevice[reader_index].ccid.sIFD_iManufacturer)
			free(usbDevice[reader_index].ccid.sIFD_iManufacturer);

		if (usbDevice[reader_index].ccid.arrayOfSupportedDataRates)
			free(usbDevice[reader_index].ccid.arrayOfSupportedDataRates);

		(void)libusb_release_interface(usbDevice[reader_index].dev_handle,
			usbDevice[reader_index].interface);
		(void)libusb_close(usbDevice[reader_index].dev_handle);
	}

	/* mark the resource unused */
	usbDevice[reader_index].dev_handle = NULL;
	usbDevice[reader_index].interface = 0;

	close_libusb_if_needed();

	return STATUS_SUCCESS;
} /* CloseUSB */
Esempio n. 10
0
/*****************************************************************************
 *
 *				OpenSerialByName: open the port
 *
 *****************************************************************************/
status_t OpenSerialByName(unsigned int reader_index, char *dev_name)
{
	struct termios current_termios;
	unsigned int reader = reader_index;
	/* 255 is MAX_DEVICENAME in pcscd.h */
	char reader_name[255] = "GemPCTwin";
	char *p;
	status_t ret;

	DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, dev_name);

	/* parse dev_name using the pattern "device:name" */
	p = strchr(dev_name, ':');
	if (p)
	{
		/* copy the second part of the string */
		strlcpy(reader_name, p+1, sizeof(reader_name));

		/* replace ':' by '\0' so that dev_name only contains the device name */
		*p = '\0';
	}

	ret = set_ccid_descriptor(reader_index, reader_name, dev_name);
	if (STATUS_UNSUCCESSFUL == ret)
		return STATUS_UNSUCCESSFUL;

	/* secondary slot so do not physically open the device */
	if (STATUS_SECONDARY_SLOT == ret)
		return STATUS_SUCCESS;

	serialDevice[reader].fd = open(dev_name, O_RDWR | O_NOCTTY);

	if (-1 == serialDevice[reader].fd)
	{
		DEBUG_CRITICAL3("open %s: %s", dev_name, strerror(errno));
		return STATUS_UNSUCCESSFUL;
	}

	/* Set RTS signal to low to prevent the smart card reader
	 * from sending its plug and play string. */
	{
		int flags;

		if (ioctl(serialDevice[reader].fd, TIOCMGET, &flags) < 0)
		{
			DEBUG_CRITICAL2("Get RS232 signals state failed: %s",
				strerror(errno));
		}
		else
		{
			flags &= ~TIOCM_RTS;
			if (ioctl(serialDevice[reader].fd, TIOCMSET, &flags) < 0)
			{
				DEBUG_CRITICAL2("Set RTS to low failed: %s", strerror(errno));
			}
			else
			{
				DEBUG_COMM("Plug-n-Play inhibition successful");
			}
		}
	}

	/* set channel used */
	serialDevice[reader].device = strdup(dev_name);

	/* empty in and out serial buffers */
	if (tcflush(serialDevice[reader].fd, TCIOFLUSH))
			DEBUG_INFO2("tcflush() function error: %s", strerror(errno));

	/* get config attributes */
	if (tcgetattr(serialDevice[reader].fd, &current_termios) == -1)
	{
		DEBUG_INFO2("tcgetattr() function error: %s", strerror(errno));
		(void)close(serialDevice[reader].fd);
		serialDevice[reader].fd = -1;

		return STATUS_UNSUCCESSFUL;
	}

	/* IGNBRK: ignore BREAK condition on input
	 * IGNPAR: ignore framing errors and parity errors. */
	current_termios.c_iflag = IGNBRK | IGNPAR;
	current_termios.c_oflag = 0;	/* Raw output modes */
	/* CS8: 8-bits character size
	 * CSTOPB: set two stop bits
	 * CREAD: enable receiver
	 * CLOCAL: ignore modem control lines */
	current_termios.c_cflag = CS8 | CSTOPB | CREAD | CLOCAL;

	/* Do not echo characters because if you connect to a host it or your modem
	 * will echo characters for you.  Don't generate signals. */
	current_termios.c_lflag = 0;

	#ifndef ANDROID
	/* set serial port speed to 115200 bauds */
	(void)cfsetspeed(&current_termios, B115200);

	DEBUG_INFO("Set serial port baudrate to 115200 and correct configuration");
	#endif
	if (tcsetattr(serialDevice[reader].fd, TCSANOW, &current_termios) == -1)
	{
		(void)close(serialDevice[reader].fd);
		serialDevice[reader].fd = -1;
		DEBUG_INFO2("tcsetattr error: %s", strerror(errno));

		return STATUS_UNSUCCESSFUL;
	}

	/* perform a command to be sure a Gemalto reader is connected
	 * get the reader firmware */
	{
		unsigned char tx_buffer[] = { 0x02 };
		unsigned char rx_buffer[50];
		unsigned int rx_length = sizeof(rx_buffer);

		/* 2 seconds timeout to not wait too long if no reader is connected */
		serialDevice[reader].ccid.readTimeout = 2*1000;

		if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer),
			rx_buffer, &rx_length))
		{
			DEBUG_CRITICAL("Get firmware failed. Maybe the reader is not connected");
			(void)CloseSerial(reader_index);
			return STATUS_UNSUCCESSFUL;
		}

		/* normal timeout: 2 seconds */
		serialDevice[reader].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT ;

		rx_buffer[rx_length] = '\0';
		DEBUG_INFO2("Firmware: %s", rx_buffer);
	}

	/* perform a command to configure GemPC Twin reader card movement
	 * notification to synchronous mode: the card movement is notified _after_
	 * the host command and _before_ the reader anwser */
	{
		unsigned char tx_buffer[] = { 0x01, 0x01, 0x01};
		unsigned char rx_buffer[50];
		unsigned int rx_length = sizeof(rx_buffer);

		if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer),
			rx_buffer, &rx_length))
		{
			DEBUG_CRITICAL("Change card movement notification failed.");
			(void)CloseSerial(reader_index);
			return STATUS_UNSUCCESSFUL;
		}
	}

	serialDevice[reader_index].ccid.sIFD_serial_number = NULL;
	serialDevice[reader_index].ccid.sIFD_iManufacturer = NULL;
	serialDevice[reader_index].ccid.IFD_bcdDevice = 0;

	return STATUS_SUCCESS;
} /* OpenSerialByName */