Blame src/parse.c

Packit 9f0df5
/*
Packit 9f0df5
    parse.c: parse CCID structure
Packit 9f0df5
    Copyright (C) 2003-2010   Ludovic Rousseau
Packit 9f0df5
Packit 9f0df5
    This program is free software; you can redistribute it and/or modify
Packit 9f0df5
    it under the terms of the GNU General Public License as published by
Packit 9f0df5
    the Free Software Foundation; either version 2 of the License, or
Packit 9f0df5
    (at your option) any later version.
Packit 9f0df5
Packit 9f0df5
    This program is distributed in the hope that it will be useful,
Packit 9f0df5
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 9f0df5
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 9f0df5
    GNU General Public License for more details.
Packit 9f0df5
Packit 9f0df5
	You should have received a copy of the GNU General Public License along
Packit 9f0df5
	with this program; if not, write to the Free Software Foundation, Inc., 51
Packit 9f0df5
	Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 9f0df5
*/
Packit 9f0df5
Packit 9f0df5
#include <stdio.h>
Packit 9f0df5
#include <string.h>
Packit 9f0df5
# ifdef S_SPLINT_S
Packit 9f0df5
# include <sys/types.h>
Packit 9f0df5
# endif
Packit 9f0df5
#include <errno.h>
Packit 9f0df5
#include <unistd.h>
Packit 9f0df5
Packit 9f0df5
#include "defs.h"
Packit 9f0df5
#include "ccid.h"
Packit 9f0df5
Packit 9f0df5
/* define DISPLAY_EXTRA_VALUES to display the extra (invalid) values
Packit 9f0df5
 * returned by bNumClockSupported and bNumDataRatesSupported */
Packit 9f0df5
#undef DISPLAY_EXTRA_VALUES
Packit 9f0df5
Packit 9f0df5
#ifndef TRUE
Packit 9f0df5
#define TRUE 1
Packit 9f0df5
#define FALSE 0
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
#define BLUE "\33[34m"
Packit 9f0df5
#define RED "\33[31m"
Packit 9f0df5
#define BRIGHT_RED "\33[01;31m"
Packit 9f0df5
#define GREEN "\33[32m"
Packit 9f0df5
#define MAGENTA "\33[35m"
Packit 9f0df5
#define NORMAL "\33[0m"
Packit 9f0df5
Packit 9f0df5
/* global variables used in ccid_usb.c but defined in ifdhandler.c */
Packit 9f0df5
int LogLevel = 1+2+4+8; /* full debug */
Packit 9f0df5
int DriverOptions = 0;
Packit 9f0df5
Packit 9f0df5
static int ccid_parse_interface_descriptor(libusb_device_handle *handle,
Packit 9f0df5
	struct libusb_device_descriptor desc,
Packit 9f0df5
	struct libusb_config_descriptor *config_desc,
Packit 9f0df5
	int num,
Packit 9f0df5
	const struct libusb_interface *usb_interface);
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *					main
Packit 9f0df5
 *
Packit 9f0df5
 ****************************************************************************/
Packit 9f0df5
int main(int argc, char *argv[])
Packit 9f0df5
{
Packit 9f0df5
	libusb_device **devs, *dev;
Packit 9f0df5
	int nb = 0, r, i;
Packit 9f0df5
	unsigned char buffer[256];
Packit 9f0df5
	char class_ff = FALSE;
Packit 9f0df5
	ssize_t cnt;
Packit 9f0df5
Packit 9f0df5
	if ((argc > 1) && (0 == strcmp(argv[1], "-p")))
Packit 9f0df5
		class_ff = TRUE;
Packit 9f0df5
Packit 9f0df5
	r = libusb_init(NULL);
Packit 9f0df5
	if (r < 0)
Packit 9f0df5
	{
Packit 9f0df5
		(void)printf("libusb_init() failed\n");
Packit 9f0df5
        return r;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	cnt = libusb_get_device_list(NULL, &devs);
Packit 9f0df5
    if (cnt < 0)
Packit 9f0df5
	{
Packit 9f0df5
		(void)printf("libusb_get_device_list() failed\n");
Packit 9f0df5
        return (int)cnt;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* for every device */
Packit 9f0df5
	i = 0;
Packit 9f0df5
	while ((dev = devs[i++]) != NULL)
Packit 9f0df5
	{
Packit 9f0df5
		struct libusb_device_descriptor desc;
Packit 9f0df5
		struct libusb_config_descriptor *config_desc;
Packit 9f0df5
		struct libusb_device_handle *handle;
Packit 9f0df5
		const struct libusb_interface *usb_interface = NULL;
Packit 9f0df5
#ifndef __APPLE__
Packit 9f0df5
		int interface;
Packit 9f0df5
#endif
Packit 9f0df5
		int num = 0;
Packit 9f0df5
Packit 9f0df5
		r = libusb_open(dev, &handle);
Packit 9f0df5
		if (r < 0)
Packit 9f0df5
		{
Packit 9f0df5
			(void)fprintf(stderr, "Can't libusb_open(): %s\n", strerror(errno));
Packit 9f0df5
			if (getuid())
Packit 9f0df5
			{
Packit 9f0df5
				(void)fprintf(stderr,
Packit 9f0df5
					BRIGHT_RED "Please, restart the command as root\n" NORMAL);
Packit 9f0df5
				return 1;
Packit 9f0df5
			}
Packit 9f0df5
			continue;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		r = libusb_get_device_descriptor(dev, &desc);
Packit 9f0df5
        if (r < 0)
Packit 9f0df5
		{
Packit 9f0df5
            (void)fprintf(stderr,
Packit 9f0df5
				BRIGHT_RED "failed to get device descriptor" NORMAL);
Packit 9f0df5
            return 1;
Packit 9f0df5
        }
Packit 9f0df5
Packit 9f0df5
		(void)fprintf(stderr,
Packit 9f0df5
			"Parsing USB bus/device: %04X:%04X (bus %d, device %d)\n",
Packit 9f0df5
			desc.idVendor, desc.idProduct,
Packit 9f0df5
            libusb_get_bus_number(dev), libusb_get_device_address(dev));
Packit 9f0df5
Packit 9f0df5
		(void)fprintf(stderr, " idVendor:  0x%04X", desc.idVendor);
Packit 9f0df5
		r = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer,
Packit 9f0df5
			buffer, sizeof(buffer));
Packit 9f0df5
		if (r < 0)
Packit 9f0df5
		{
Packit 9f0df5
			(void)fprintf(stderr, "  Can't get iManufacturer string\n");
Packit 9f0df5
			if (getuid())
Packit 9f0df5
			{
Packit 9f0df5
				(void)fprintf(stderr,
Packit 9f0df5
					BRIGHT_RED "Please, restart the command as root\n" NORMAL);
Packit 9f0df5
				return 1;
Packit 9f0df5
			}
Packit 9f0df5
		}
Packit 9f0df5
		else
Packit 9f0df5
			(void)fprintf(stderr,
Packit 9f0df5
				"  iManufacturer: " BLUE "%s\n" NORMAL, buffer);
Packit 9f0df5
Packit 9f0df5
		(void)fprintf(stderr, " idProduct: 0x%04X", desc.idProduct);
Packit 9f0df5
		r = libusb_get_string_descriptor_ascii(handle, desc.iProduct,
Packit 9f0df5
			buffer, sizeof(buffer));
Packit 9f0df5
		if (r < 0)
Packit 9f0df5
			(void)fprintf(stderr, "  Can't get iProduct string\n");
Packit 9f0df5
		else
Packit 9f0df5
			(void)fprintf(stderr, "  iProduct: " BLUE "%s\n" NORMAL, buffer);
Packit 9f0df5
Packit 9f0df5
again:
Packit 9f0df5
		/* check if the device has bInterfaceClass == 11 */
Packit 9f0df5
		r = libusb_get_active_config_descriptor(dev, &config_desc);
Packit 9f0df5
		if (r < 0)
Packit 9f0df5
		{
Packit 9f0df5
			(void)fprintf(stderr, "  Can't get config descriptor: %d\n", r);
Packit 9f0df5
			(void)libusb_close(handle);
Packit 9f0df5
			continue;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		usb_interface = get_ccid_usb_interface(config_desc, &num);
Packit 9f0df5
		if (NULL == usb_interface)
Packit 9f0df5
		{
Packit 9f0df5
			(void)libusb_close(handle);
Packit 9f0df5
			/* only if we found no CCID interface */
Packit 9f0df5
			if (0 == num)
Packit 9f0df5
				(void)fprintf(stderr, RED "  NOT a CCID/ICCD device\n" NORMAL);
Packit 9f0df5
			continue;
Packit 9f0df5
		}
Packit 9f0df5
		if (!class_ff && (0xFF == usb_interface->altsetting->bInterfaceClass))
Packit 9f0df5
		{
Packit 9f0df5
			(void)libusb_close(handle);
Packit 9f0df5
			(void)fprintf(stderr, MAGENTA "  Found a possibly CCID/ICCD device (bInterfaceClass = 0xFF). Use %s -p\n" NORMAL, argv[0]);
Packit 9f0df5
			continue;
Packit 9f0df5
		}
Packit 9f0df5
		(void)fprintf(stderr,
Packit 9f0df5
			GREEN "  Found a CCID/ICCD device at interface %d\n" NORMAL, num);
Packit 9f0df5
Packit 9f0df5
		/* now we found a free reader and we try to use it */
Packit 9f0df5
#if 0
Packit 9f0df5
		if (NULL == dev->config)
Packit 9f0df5
		{
Packit 9f0df5
			(void)libusb_close(handle);
Packit 9f0df5
			(void)fprintf(stderr, "No dev->config found for %s/%s\n",
Packit 9f0df5
					bus->dirname, dev->filename);
Packit 9f0df5
			continue;
Packit 9f0df5
		}
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
#ifndef __APPLE__
Packit 9f0df5
		interface = usb_interface->altsetting->bInterfaceNumber;
Packit 9f0df5
		r = libusb_claim_interface(handle, interface);
Packit 9f0df5
		if (r < 0)
Packit 9f0df5
		{
Packit 9f0df5
			(void)fprintf(stderr,
Packit 9f0df5
				"Can't claim interface (bus %d, device %d): %s\n",
Packit 9f0df5
				libusb_get_bus_number(dev), libusb_get_device_address(dev),
Packit 9f0df5
				strerror(errno));
Packit 9f0df5
			(void)libusb_close(handle);
Packit 9f0df5
Packit 9f0df5
			if (EBUSY == errno)
Packit 9f0df5
			{
Packit 9f0df5
				(void)fprintf(stderr,
Packit 9f0df5
					BRIGHT_RED " Please, stop pcscd and retry\n\n" NORMAL);
Packit 9f0df5
Packit 9f0df5
				if (class_ff)
Packit 9f0df5
					/* maybe the device with Class = 0xFF is NOT a CCID
Packit 9f0df5
					 * reader */
Packit 9f0df5
					continue;
Packit 9f0df5
				else
Packit 9f0df5
					return TRUE;
Packit 9f0df5
			}
Packit 9f0df5
			continue;
Packit 9f0df5
		}
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
		(void)ccid_parse_interface_descriptor(handle, desc, config_desc, num,
Packit 9f0df5
			usb_interface);
Packit 9f0df5
		nb++;
Packit 9f0df5
Packit 9f0df5
#ifndef __APPLE__
Packit 9f0df5
		(void)libusb_release_interface(handle, interface);
Packit 9f0df5
#endif
Packit 9f0df5
		/* check for another CCID interface on the same device */
Packit 9f0df5
		num++;
Packit 9f0df5
		goto again;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	if ((0 == nb) && (0 != geteuid()))
Packit 9f0df5
		(void)fprintf(stderr,
Packit 9f0df5
			"Can't find any CCID device.\nMaybe you must run parse as root?\n");
Packit 9f0df5
Packit 9f0df5
	libusb_exit(NULL);
Packit 9f0df5
Packit 9f0df5
	return 0;
Packit 9f0df5
} /* main */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *					Parse a CCID USB Descriptor
Packit 9f0df5
 *
Packit 9f0df5
 ****************************************************************************/
Packit 9f0df5
static int ccid_parse_interface_descriptor(libusb_device_handle *handle,
Packit 9f0df5
	struct libusb_device_descriptor desc,
Packit 9f0df5
	struct libusb_config_descriptor *config_desc,
Packit 9f0df5
	int num,
Packit 9f0df5
	const struct libusb_interface *usb_interface)
Packit 9f0df5
{
Packit 9f0df5
	const struct libusb_interface_descriptor *usb_interface_descriptor;
Packit 9f0df5
	const unsigned char *device_descriptor;
Packit 9f0df5
	unsigned char buffer[256*sizeof(int)];  /* maximum is 256 records */
Packit 9f0df5
	int r;
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * Vendor/model name
Packit 9f0df5
	 */
Packit 9f0df5
	(void)printf(" idVendor: 0x%04X\n", desc.idVendor);
Packit 9f0df5
	r = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer,
Packit 9f0df5
		buffer, sizeof(buffer));
Packit 9f0df5
	if (r < 0)
Packit 9f0df5
	{
Packit 9f0df5
		(void)printf("  Can't get iManufacturer string\n");
Packit 9f0df5
		if (getuid())
Packit 9f0df5
		{
Packit 9f0df5
			(void)fprintf(stderr,
Packit 9f0df5
				BRIGHT_RED "Please, restart the command as root\n\n" NORMAL);
Packit 9f0df5
			return TRUE;
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
	else
Packit 9f0df5
		(void)printf("  iManufacturer: %s\n", buffer);
Packit 9f0df5
Packit 9f0df5
	(void)printf(" idProduct: 0x%04X\n", desc.idProduct);
Packit 9f0df5
	r =  libusb_get_string_descriptor_ascii(handle, desc.iProduct,
Packit 9f0df5
		buffer, sizeof(buffer));
Packit 9f0df5
	if (r < 0)
Packit 9f0df5
		(void)printf("  Can't get iProduct string\n");
Packit 9f0df5
	else
Packit 9f0df5
		(void)printf("  iProduct: %s\n", buffer);
Packit 9f0df5
Packit 9f0df5
	(void)printf(" bcdDevice: %X.%02X (firmware release?)\n",
Packit 9f0df5
		desc.bcdDevice >> 8, desc.bcdDevice & 0xFF);
Packit 9f0df5
Packit 9f0df5
	usb_interface_descriptor = get_ccid_usb_interface(config_desc, &num)->altsetting;
Packit 9f0df5
Packit 9f0df5
	(void)printf(" bLength: %d\n", usb_interface_descriptor->bLength);
Packit 9f0df5
Packit 9f0df5
	(void)printf(" bDescriptorType: %d\n", usb_interface_descriptor->bDescriptorType);
Packit 9f0df5
Packit 9f0df5
	(void)printf(" bInterfaceNumber: %d\n", usb_interface_descriptor->bInterfaceNumber);
Packit 9f0df5
Packit 9f0df5
	(void)printf(" bAlternateSetting: %d\n", usb_interface_descriptor->bAlternateSetting);
Packit 9f0df5
Packit 9f0df5
	(void)printf(" bNumEndpoints: %d\n", usb_interface_descriptor->bNumEndpoints);
Packit 9f0df5
	switch (usb_interface_descriptor->bNumEndpoints)
Packit 9f0df5
	{
Packit 9f0df5
		case 0:
Packit 9f0df5
			(void)printf("  Control only\n");
Packit 9f0df5
			break;
Packit 9f0df5
		case 1:
Packit 9f0df5
			(void)printf("  Interrupt-IN\n");
Packit 9f0df5
			break;
Packit 9f0df5
		case 2:
Packit 9f0df5
			(void)printf("  bulk-IN and bulk-OUT\n");
Packit 9f0df5
			break;
Packit 9f0df5
		case 3:
Packit 9f0df5
			(void)printf("  bulk-IN, bulk-OUT and Interrupt-IN\n");
Packit 9f0df5
			break;
Packit 9f0df5
		default:
Packit 9f0df5
			(void)printf("  UNKNOWN value\n");
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	(void)printf(" bInterfaceClass: 0x%02X", usb_interface_descriptor->bInterfaceClass);
Packit 9f0df5
	if (usb_interface_descriptor->bInterfaceClass == 0x0b)
Packit 9f0df5
		(void)printf(" [Chip Card Interface Device Class (CCID)]\n");
Packit 9f0df5
	else
Packit 9f0df5
	{
Packit 9f0df5
		(void)printf("\n  NOT A CCID DEVICE\n");
Packit 9f0df5
		if (usb_interface_descriptor->bInterfaceClass != 0xFF)
Packit 9f0df5
			return TRUE;
Packit 9f0df5
		else
Packit 9f0df5
			(void)printf("  Class is 0xFF (proprietary)\n");
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	(void)printf(" bInterfaceSubClass: %d\n",
Packit 9f0df5
		usb_interface_descriptor->bInterfaceSubClass);
Packit 9f0df5
	if (usb_interface_descriptor->bInterfaceSubClass)
Packit 9f0df5
		(void)printf("  UNSUPPORTED SubClass\n");
Packit 9f0df5
Packit 9f0df5
	(void)printf(" bInterfaceProtocol: %d\n",
Packit 9f0df5
		usb_interface_descriptor->bInterfaceProtocol);
Packit 9f0df5
	switch (usb_interface_descriptor->bInterfaceProtocol)
Packit 9f0df5
	{
Packit 9f0df5
		case 0:
Packit 9f0df5
			(void)printf("  bulk transfer, optional interrupt-IN (CCID)\n");
Packit 9f0df5
			break;
Packit 9f0df5
		case 1:
Packit 9f0df5
			(void)printf("  ICCD Version A, Control transfers, (no interrupt-IN)\n");
Packit 9f0df5
			break;
Packit 9f0df5
		case 2:
Packit 9f0df5
			(void)printf("  ICCD Version B, Control transfers, (optional interrupt-IN)\n");
Packit 9f0df5
			break;
Packit 9f0df5
		default:
Packit 9f0df5
			(void)printf("  UNSUPPORTED InterfaceProtocol\n");
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	r = libusb_get_string_descriptor_ascii(handle, usb_interface_descriptor->iInterface,
Packit 9f0df5
		buffer, sizeof(buffer));
Packit 9f0df5
	if (r < 0)
Packit 9f0df5
		(void)printf(" Can't get iInterface string\n");
Packit 9f0df5
	else
Packit 9f0df5
		(void)printf(" iInterface: %s\n", buffer);
Packit 9f0df5
Packit 9f0df5
	device_descriptor = get_ccid_device_descriptor(usb_interface);
Packit 9f0df5
	if (NULL == device_descriptor)
Packit 9f0df5
	{
Packit 9f0df5
		(void)printf("\n  NOT A CCID DEVICE\n");
Packit 9f0df5
		return TRUE;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * CCID Class Descriptor
Packit 9f0df5
	 */
Packit 9f0df5
	(void)printf(" CCID Class Descriptor\n");
Packit 9f0df5
Packit 9f0df5
	(void)printf("  bLength: 0x%02X\n", device_descriptor[0]);
Packit 9f0df5
	if (device_descriptor[0] != 0x36)
Packit 9f0df5
	{
Packit 9f0df5
		(void)printf("   UNSUPPORTED bLength\n");
Packit 9f0df5
		return TRUE;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	(void)printf("  bDescriptorType: 0x%02X\n", device_descriptor[1]);
Packit 9f0df5
	if (device_descriptor[1] != 0x21)
Packit 9f0df5
	{
Packit 9f0df5
		if (0xFF == device_descriptor[1])
Packit 9f0df5
			(void)printf("   PROPRIETARY bDescriptorType\n");
Packit 9f0df5
		else
Packit 9f0df5
		{
Packit 9f0df5
			(void)printf("   UNSUPPORTED bDescriptorType\n");
Packit 9f0df5
			return TRUE;
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	(void)printf("  bcdCCID: %X.%02X\n", device_descriptor[3], device_descriptor[2]);
Packit 9f0df5
	(void)printf("  bMaxSlotIndex: 0x%02X\n", device_descriptor[4]);
Packit 9f0df5
	(void)printf("  bVoltageSupport: 0x%02X\n", device_descriptor[5]);
Packit 9f0df5
	if (device_descriptor[5] & 0x01)
Packit 9f0df5
		(void)printf("   5.0V\n");
Packit 9f0df5
	if (device_descriptor[5] & 0x02)
Packit 9f0df5
		(void)printf("   3.0V\n");
Packit 9f0df5
	if (device_descriptor[5] & 0x04)
Packit 9f0df5
		(void)printf("   1.8V\n");
Packit 9f0df5
Packit 9f0df5
	(void)printf("  dwProtocols: 0x%02X%02X 0x%02X%02X\n", device_descriptor[9], device_descriptor[8],
Packit 9f0df5
		device_descriptor[7], device_descriptor[6]);
Packit 9f0df5
	if (device_descriptor[6] & 0x01)
Packit 9f0df5
		(void)printf("   T=0\n");
Packit 9f0df5
	if (device_descriptor[6] & 0x02)
Packit 9f0df5
		(void)printf("   T=1\n");
Packit 9f0df5
Packit 9f0df5
	(void)printf("  dwDefaultClock: %.3f MHz\n", dw2i(device_descriptor, 10)/1000.0);
Packit 9f0df5
	(void)printf("  dwMaximumClock: %.3f MHz\n", dw2i(device_descriptor, 14)/1000.0);
Packit 9f0df5
	(void)printf("  bNumClockSupported: %d%s\n", device_descriptor[18],
Packit 9f0df5
		device_descriptor[18] ? "" : " (will use whatever is returned)");
Packit 9f0df5
	{
Packit 9f0df5
		int n;
Packit 9f0df5
Packit 9f0df5
		/* See CCID 3.7.2 page 25 */
Packit 9f0df5
		n = libusb_control_transfer(handle,
Packit 9f0df5
			0xA1, /* request type */
Packit 9f0df5
			0x02, /* GET CLOCK FREQUENCIES */
Packit 9f0df5
			0x00, /* value */
Packit 9f0df5
			usb_interface_descriptor->bInterfaceNumber, /* interface */
Packit 9f0df5
			buffer,
Packit 9f0df5
			sizeof(buffer),
Packit 9f0df5
			2 * 1000);
Packit 9f0df5
Packit 9f0df5
		/* we got an error? */
Packit 9f0df5
		if (n <= 0)
Packit 9f0df5
		{
Packit 9f0df5
			(void)(void)printf("   IFD does not support GET CLOCK FREQUENCIES request: %s\n", strerror(errno));
Packit 9f0df5
			if (EBUSY == errno)
Packit 9f0df5
			{
Packit 9f0df5
				(void)fprintf(stderr,
Packit 9f0df5
					BRIGHT_RED "   Please, stop pcscd and retry\n\n" NORMAL);
Packit 9f0df5
				return TRUE;
Packit 9f0df5
			}
Packit 9f0df5
		}
Packit 9f0df5
		else
Packit 9f0df5
			if (n % 4)	/* not a multiple of 4 */
Packit 9f0df5
				(void)printf("   wrong size for GET CLOCK FREQUENCIES: %d\n", n);
Packit 9f0df5
			else
Packit 9f0df5
			{
Packit 9f0df5
				int i;
Packit 9f0df5
Packit 9f0df5
				/* we do not get the expected number of data rates */
Packit 9f0df5
				if ((n != device_descriptor[18]*4) && device_descriptor[18])
Packit 9f0df5
				{
Packit 9f0df5
					(void)printf("   Got %d clock frequencies but was expecting %d\n",
Packit 9f0df5
						n/4, device_descriptor[18]);
Packit 9f0df5
Packit 9f0df5
					/* we got more data than expected */
Packit 9f0df5
#ifndef DISPLAY_EXTRA_VALUES
Packit 9f0df5
					if (n > device_descriptor[18]*4)
Packit 9f0df5
						n = device_descriptor[18]*4;
Packit 9f0df5
#endif
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				for (i=0; i
Packit 9f0df5
					(void)printf("   Support %d kHz\n", dw2i(buffer, i));
Packit 9f0df5
			}
Packit 9f0df5
	}
Packit 9f0df5
	(void)printf("  dwDataRate: %d bps\n", dw2i(device_descriptor, 19));
Packit 9f0df5
	(void)printf("  dwMaxDataRate: %d bps\n", dw2i(device_descriptor, 23));
Packit 9f0df5
	(void)printf("  bNumDataRatesSupported: %d%s\n", device_descriptor[27],
Packit 9f0df5
		device_descriptor[27] ? "" : " (will use whatever is returned)");
Packit 9f0df5
	{
Packit 9f0df5
		int n;
Packit 9f0df5
Packit 9f0df5
		/* See CCID 3.7.3 page 25 */
Packit 9f0df5
		n = libusb_control_transfer(handle,
Packit 9f0df5
			0xA1, /* request type */
Packit 9f0df5
			0x03, /* GET DATA RATES */
Packit 9f0df5
			0x00, /* value */
Packit 9f0df5
			usb_interface_descriptor->bInterfaceNumber, /* interface */
Packit 9f0df5
			buffer,
Packit 9f0df5
			sizeof(buffer),
Packit 9f0df5
			2 * 1000);
Packit 9f0df5
Packit 9f0df5
		/* we got an error? */
Packit 9f0df5
		if (n <= 0)
Packit 9f0df5
			(void)printf("   IFD does not support GET_DATA_RATES request: %s\n",
Packit 9f0df5
				strerror(errno));
Packit 9f0df5
		else
Packit 9f0df5
			if (n % 4)	/* not a multiple of 4 */
Packit 9f0df5
				(void)printf("   wrong size for GET_DATA_RATES: %d\n", n);
Packit 9f0df5
			else
Packit 9f0df5
			{
Packit 9f0df5
				int i;
Packit 9f0df5
Packit 9f0df5
				/* we do not get the expected number of data rates */
Packit 9f0df5
				if ((n != device_descriptor[27]*4) && device_descriptor[27])
Packit 9f0df5
				{
Packit 9f0df5
					(void)printf("   Got %d data rates but was expecting %d\n", n/4,
Packit 9f0df5
						device_descriptor[27]);
Packit 9f0df5
Packit 9f0df5
					/* we got more data than expected */
Packit 9f0df5
#ifndef DISPLAY_EXTRA_VALUES
Packit 9f0df5
					if (n > device_descriptor[27]*4)
Packit 9f0df5
						n = device_descriptor[27]*4;
Packit 9f0df5
#endif
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				for (i=0; i
Packit 9f0df5
					(void)printf("   Support %d bps\n", dw2i(buffer, i));
Packit 9f0df5
			}
Packit 9f0df5
	}
Packit 9f0df5
	(void)printf("  dwMaxIFSD: %d\n", dw2i(device_descriptor, 28));
Packit 9f0df5
	(void)printf("  dwSynchProtocols: 0x%08X\n", dw2i(device_descriptor, 32));
Packit 9f0df5
	if (device_descriptor[32] & 0x01)
Packit 9f0df5
			(void)printf("   2-wire protocol\n");
Packit 9f0df5
	if (device_descriptor[32] & 0x02)
Packit 9f0df5
			(void)printf("   3-wire protocol\n");
Packit 9f0df5
	if (device_descriptor[32] & 0x04)
Packit 9f0df5
			(void)printf("   I2C protocol\n");
Packit 9f0df5
Packit 9f0df5
	(void)printf("  dwMechanical: 0x%08X\n", dw2i(device_descriptor, 36));
Packit 9f0df5
	if (device_descriptor[36] == 0)
Packit 9f0df5
		(void)printf("   No special characteristics\n");
Packit 9f0df5
	if (device_descriptor[36] & 0x01)
Packit 9f0df5
		(void)printf("   Card accept mechanism\n");
Packit 9f0df5
	if (device_descriptor[36] & 0x02)
Packit 9f0df5
		(void)printf("   Card ejection mechanism\n");
Packit 9f0df5
	if (device_descriptor[36] & 0x04)
Packit 9f0df5
		(void)printf("   Card capture mechanism\n");
Packit 9f0df5
	if (device_descriptor[36] & 0x08)
Packit 9f0df5
		(void)printf("   Card lock/unlock mechanism\n");
Packit 9f0df5
Packit 9f0df5
	(void)printf("  dwFeatures: 0x%08X\n", dw2i(device_descriptor, 40));
Packit 9f0df5
	if (dw2i(device_descriptor, 40) == 0)
Packit 9f0df5
		(void)printf("   No special characteristics\n");
Packit 9f0df5
	if (device_descriptor[40] & 0x02)
Packit 9f0df5
		(void)printf("   ....02 Automatic parameter configuration based on ATR data\n");
Packit 9f0df5
	if (device_descriptor[40] & 0x04)
Packit 9f0df5
		(void)printf("   ....04 Automatic activation of ICC on inserting\n");
Packit 9f0df5
	if (device_descriptor[40] & 0x08)
Packit 9f0df5
		(void)printf("   ....08 Automatic ICC voltage selection\n");
Packit 9f0df5
	if (device_descriptor[40] & 0x10)
Packit 9f0df5
		(void)printf("   ....10 Automatic ICC clock frequency change according to parameters\n");
Packit 9f0df5
	if (device_descriptor[40] & 0x20)
Packit 9f0df5
		(void)printf("   ....20 Automatic baud rate change according to frequency and Fi, Di params\n");
Packit 9f0df5
	if (device_descriptor[40] & 0x40)
Packit 9f0df5
		(void)printf("   ....40 Automatic parameters negotiation made by the CCID\n");
Packit 9f0df5
	if (device_descriptor[40] & 0x80)
Packit 9f0df5
		(void)printf("   ....80 Automatic PPS made by the CCID\n");
Packit 9f0df5
	if (device_descriptor[41] & 0x01)
Packit 9f0df5
		(void)printf("   ..01.. CCID can set ICC in clock stop mode\n");
Packit 9f0df5
	if (device_descriptor[41] & 0x02)
Packit 9f0df5
		(void)printf("   ..02.. NAD value other than 00 accepted (T=1)\n");
Packit 9f0df5
	if (device_descriptor[41] & 0x04)
Packit 9f0df5
		(void)printf("   ..04.. Automatic IFSD exchange as first exchange (T=1)\n");
Packit 9f0df5
	if (device_descriptor[41] & 0x08)
Packit 9f0df5
		(void)printf("   ..08.. Unknown (ICCD?)\n");
Packit 9f0df5
	switch (device_descriptor[42] & 0x07)
Packit 9f0df5
	{
Packit 9f0df5
		case 0x00:
Packit 9f0df5
			(void)printf("   00.... Character level exchange\n");
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case 0x01:
Packit 9f0df5
			(void)printf("   01.... TPDU level exchange\n");
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case 0x02:
Packit 9f0df5
			(void)printf("   02.... Short APDU level exchange\n");
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case 0x04:
Packit 9f0df5
			(void)printf("   04.... Short and Extended APDU level exchange\n");
Packit 9f0df5
			break;
Packit 9f0df5
	}
Packit 9f0df5
	if (device_descriptor[42] & 0x10)
Packit 9f0df5
		(void)printf("   10.... USB Wake up signaling supported on card insertion and removal\n");
Packit 9f0df5
Packit 9f0df5
	(void)printf("  dwMaxCCIDMessageLength: %d bytes\n", dw2i(device_descriptor, 44));
Packit 9f0df5
	(void)printf("  bClassGetResponse: 0x%02X\n", device_descriptor[48]);
Packit 9f0df5
	if (0xFF == device_descriptor[48])
Packit 9f0df5
		(void)printf("   echoes the APDU class\n");
Packit 9f0df5
	(void)printf("  bClassEnvelope: 0x%02X\n", device_descriptor[49]);
Packit 9f0df5
	if (0xFF == device_descriptor[49])
Packit 9f0df5
		(void)printf("   echoes the APDU class\n");
Packit 9f0df5
	(void)printf("  wLcdLayout: 0x%04X\n", (device_descriptor[51] << 8)+device_descriptor[50]);
Packit 9f0df5
	if (device_descriptor[51])
Packit 9f0df5
		(void)printf("   %2d lines\n", device_descriptor[51]);
Packit 9f0df5
	if (device_descriptor[50])
Packit 9f0df5
		(void)printf("   %2d characters per line\n", device_descriptor[50]);
Packit 9f0df5
	(void)printf("  bPINSupport: 0x%02X\n", device_descriptor[52]);
Packit 9f0df5
	if (device_descriptor[52] & 0x01)
Packit 9f0df5
		(void)printf("   PIN Verification supported\n");
Packit 9f0df5
	if (device_descriptor[52] & 0x02)
Packit 9f0df5
		(void)printf("   PIN Modification supported\n");
Packit 9f0df5
	(void)printf("  bMaxCCIDBusySlots: %d\n", device_descriptor[53]);
Packit 9f0df5
Packit 9f0df5
	return FALSE;
Packit 9f0df5
} /* ccid_parse_interface_descriptor */
Packit 9f0df5