Blame src/ccid_serial.c

Packit 9f0df5
/*
Packit 9f0df5
 * ccid_serial.c: communicate with a GemPC Twin smart card reader
Packit 9f0df5
 * Copyright (C) 2001-2010 Ludovic Rousseau <ludovic.rousseau@free.fr>
Packit 9f0df5
 *
Packit 9f0df5
 * Thanks to Niki W. Waibel <niki.waibel@gmx.net> for a prototype version
Packit 9f0df5
 *
Packit 9f0df5
    This library is free software; you can redistribute it and/or
Packit 9f0df5
    modify it under the terms of the GNU Lesser General Public
Packit 9f0df5
    License as published by the Free Software Foundation; either
Packit 9f0df5
    version 2.1 of the License, or (at your option) any later version.
Packit 9f0df5
Packit 9f0df5
    This library 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 GNU
Packit 9f0df5
    Lesser General Public License for more details.
Packit 9f0df5
Packit 9f0df5
	You should have received a copy of the GNU Lesser General Public License
Packit 9f0df5
	along with this library; if not, write to the Free Software Foundation,
Packit 9f0df5
	Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 9f0df5
 */
Packit 9f0df5
Packit 9f0df5
#include <stdio.h>
Packit 9f0df5
#include <stdlib.h>
Packit 9f0df5
#include <fcntl.h>
Packit 9f0df5
#include <unistd.h>
Packit 9f0df5
#include <termios.h>
Packit 9f0df5
#include <string.h>
Packit 9f0df5
#include <errno.h>
Packit 9f0df5
#include <sys/time.h>
Packit 9f0df5
#include <sys/types.h>
Packit 9f0df5
#include <sys/ioctl.h>
Packit 9f0df5
#include <ifdhandler.h>
Packit 9f0df5
Packit 9f0df5
#include <config.h>
Packit 9f0df5
#include "defs.h"
Packit 9f0df5
#include "ccid_ifdhandler.h"
Packit 9f0df5
#include "debug.h"
Packit 9f0df5
#include "ccid.h"
Packit 9f0df5
#include "utils.h"
Packit 9f0df5
#include "commands.h"
Packit 9f0df5
#include "parser.h"
Packit 9f0df5
#include "strlcpycat.h"
Packit 9f0df5
Packit 9f0df5
#define SYNC 0x03
Packit 9f0df5
#define CTRL_ACK 0x06
Packit 9f0df5
#define CTRL_NAK 0x15
Packit 9f0df5
#define RDR_to_PC_NotifySlotChange 0x50
Packit 9f0df5
#define CARD_ABSENT 0x02
Packit 9f0df5
#define CARD_PRESENT 0x03
Packit 9f0df5
Packit 9f0df5
/*
Packit 9f0df5
 * normal command:
Packit 9f0df5
 * 1 : SYNC
Packit 9f0df5
 * 1 : CTRL
Packit 9f0df5
 * 10 +data length : CCID command
Packit 9f0df5
 * 1 : LRC
Packit 9f0df5
 *
Packit 9f0df5
 * SYNC : 0x03
Packit 9f0df5
 * CTRL : ACK (0x06) or NAK (0x15)
Packit 9f0df5
 * CCID command : see USB CCID specs
Packit 9f0df5
 * LRC : xor of all the previous byes
Packit 9f0df5
 *
Packit 9f0df5
 * Error message:
Packit 9f0df5
 * 1 : SYNC (0x03)
Packit 9f0df5
 * 1 : CTRL (NAK: 0x15)
Packit 9f0df5
 * 1 : LRC (0x16)
Packit 9f0df5
 *
Packit 9f0df5
 * Card insertion/withdrawal
Packit 9f0df5
 * 1 : RDR_to_PC_NotifySlotChange (0x50)
Packit 9f0df5
 * 1 : bmSlotIccState
Packit 9f0df5
 *     0x02 if card absent
Packit 9f0df5
 *     0x03 is card present
Packit 9f0df5
 *
Packit 9f0df5
 * Time request
Packit 9f0df5
 * T=1 : normal CCID command
Packit 9f0df5
 * T=0 : 1 byte (value between 0x80 and 0xFF)
Packit 9f0df5
 *
Packit 9f0df5
 */
Packit 9f0df5
Packit 9f0df5
/*
Packit 9f0df5
 * You may get read timeout after a card movement.
Packit 9f0df5
 * This is because you will get the echo of the CCID command
Packit 9f0df5
 * but not the result of the command.
Packit 9f0df5
 *
Packit 9f0df5
 * This is not an applicative issue since the card is either removed (and
Packit 9f0df5
 * powered off) or just inserted (and not yet powered on).
Packit 9f0df5
 */
Packit 9f0df5
Packit 9f0df5
/* 271 = max size for short APDU
Packit 9f0df5
 * 2 bytes for header
Packit 9f0df5
 * 1 byte checksum
Packit 9f0df5
 * doubled for echo
Packit 9f0df5
 */
Packit 9f0df5
#define GEMPCTWIN_MAXBUF (271 +2 +1) * 2
Packit 9f0df5
Packit 9f0df5
typedef struct
Packit 9f0df5
{
Packit 9f0df5
	/*
Packit 9f0df5
	 * File handle on the serial port
Packit 9f0df5
	 */
Packit 9f0df5
	int fd;
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * device used ("/dev/ttyS?" under Linux)
Packit 9f0df5
	 */
Packit 9f0df5
	/*@null@*/ char *device;
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * Number of slots using the same device
Packit 9f0df5
	 */
Packit 9f0df5
	int real_nb_opened_slots;
Packit 9f0df5
	int *nb_opened_slots;
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * does the reader echoes the serial communication bytes?
Packit 9f0df5
	 */
Packit 9f0df5
	int echo;
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * serial communication buffer
Packit 9f0df5
	 */
Packit 9f0df5
	unsigned char buffer[GEMPCTWIN_MAXBUF];
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * next available byte
Packit 9f0df5
	 */
Packit 9f0df5
	int buffer_offset;
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * number of available bytes
Packit 9f0df5
	 */
Packit 9f0df5
	int buffer_offset_last;
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * CCID infos common to USB and serial
Packit 9f0df5
	 */
Packit 9f0df5
	_ccid_descriptor ccid;
Packit 9f0df5
Packit 9f0df5
} _serialDevice;
Packit 9f0df5
Packit 9f0df5
/* The _serialDevice structure must be defined before including ccid_serial.h */
Packit 9f0df5
#include "ccid_serial.h"
Packit 9f0df5
Packit 9f0df5
/* data rates supported by the GemPC Twin (serial and PCMCIA) */
Packit 9f0df5
unsigned int SerialTwinDataRates[] = { ISO_DATA_RATES, 0 };
Packit 9f0df5
Packit 9f0df5
/* data rates supported by the GemPC PinPad, GemCore Pos Pro & SIM Pro */
Packit 9f0df5
unsigned int SerialExtendedDataRates[] = { ISO_DATA_RATES, 500000, 0 };
Packit 9f0df5
Packit 9f0df5
/* data rates supported by the secondary slots on the GemCore Pos Pro & SIM Pro */
Packit 9f0df5
unsigned int SerialCustomDataRates[] = { GEMPLUS_CUSTOM_DATA_RATES, 0 };
Packit 9f0df5
Packit 9f0df5
/* data rates supported by the GemCore SIM Pro 2 */
Packit 9f0df5
unsigned int SIMPro2DataRates[] = { SIMPRO2_ISO_DATA_RATES, 0  };
Packit 9f0df5
Packit 9f0df5
/* no need to initialize to 0 since it is static */
Packit 9f0df5
static _serialDevice serialDevice[CCID_DRIVER_MAX_READERS];
Packit 9f0df5
Packit 9f0df5
/* unexported functions */
Packit 9f0df5
static int ReadChunk(unsigned int reader_index, unsigned char *buffer,
Packit 9f0df5
	int buffer_length, int min_length);
Packit 9f0df5
Packit 9f0df5
static int get_bytes(unsigned int reader_index, /*@out@*/ unsigned char *buffer,
Packit 9f0df5
	int length);
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *				WriteSerial: Send bytes to the card reader
Packit 9f0df5
 *
Packit 9f0df5
 *****************************************************************************/
Packit 9f0df5
status_t WriteSerial(unsigned int reader_index, unsigned int length,
Packit 9f0df5
	unsigned char *buffer)
Packit 9f0df5
{
Packit 9f0df5
	unsigned int i;
Packit 9f0df5
	unsigned char lrc;
Packit 9f0df5
	unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];
Packit 9f0df5
Packit 9f0df5
	char debug_header[] = "-> 123456 ";
Packit 9f0df5
Packit 9f0df5
	(void)snprintf(debug_header, sizeof(debug_header), "-> %06X ",
Packit 9f0df5
		reader_index);
Packit 9f0df5
Packit 9f0df5
	if (length > GEMPCTWIN_MAXBUF-3)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_CRITICAL3("command too long: %d for max %d",
Packit 9f0df5
			length, GEMPCTWIN_MAXBUF-3);
Packit 9f0df5
		return STATUS_UNSUCCESSFUL;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* header */
Packit 9f0df5
	low_level_buffer[0] = 0x03;	/* SYNC */
Packit 9f0df5
	low_level_buffer[1] = 0x06;	/* ACK */
Packit 9f0df5
Packit 9f0df5
	/* CCID command */
Packit 9f0df5
	memcpy(low_level_buffer+2, buffer, length);
Packit 9f0df5
Packit 9f0df5
	/* checksum */
Packit 9f0df5
	lrc = 0;
Packit 9f0df5
	for(i=0; i
Packit 9f0df5
		lrc ^= low_level_buffer[i];
Packit 9f0df5
	low_level_buffer[length+2] = lrc;
Packit 9f0df5
Packit 9f0df5
	DEBUG_XXD(debug_header, low_level_buffer, length+3);
Packit 9f0df5
Packit 9f0df5
	if (write(serialDevice[reader_index].fd, low_level_buffer,
Packit 9f0df5
		length+3) != length+3)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_CRITICAL2("write error: %s", strerror(errno));
Packit 9f0df5
		return STATUS_UNSUCCESSFUL;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	return STATUS_SUCCESS;
Packit 9f0df5
} /* WriteSerial */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *				ReadSerial: Receive bytes from the card reader
Packit 9f0df5
 *
Packit 9f0df5
 *****************************************************************************/
Packit 9f0df5
status_t ReadSerial(unsigned int reader_index,
Packit 9f0df5
	unsigned int *length, unsigned char *buffer)
Packit 9f0df5
{
Packit 9f0df5
	unsigned char c;
Packit 9f0df5
	int rv;
Packit 9f0df5
	int echo;
Packit 9f0df5
	int to_read;
Packit 9f0df5
	int i;
Packit 9f0df5
Packit 9f0df5
	/* we get the echo first */
Packit 9f0df5
	echo = serialDevice[reader_index].echo;
Packit 9f0df5
Packit 9f0df5
start:
Packit 9f0df5
	DEBUG_COMM("start");
Packit 9f0df5
	if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
Packit 9f0df5
		return rv;
Packit 9f0df5
Packit 9f0df5
	if (c == RDR_to_PC_NotifySlotChange)
Packit 9f0df5
		goto slot_change;
Packit 9f0df5
Packit 9f0df5
	if (c == SYNC)
Packit 9f0df5
		goto sync;
Packit 9f0df5
Packit 9f0df5
	if (c >= 0x80)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_COMM2("time request: 0x%02X", c);
Packit 9f0df5
		goto start;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	DEBUG_CRITICAL2("Got 0x%02X", c);
Packit 9f0df5
	return STATUS_COMM_ERROR;
Packit 9f0df5
Packit 9f0df5
slot_change:
Packit 9f0df5
	DEBUG_COMM("slot change");
Packit 9f0df5
	if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
Packit 9f0df5
		return rv;
Packit 9f0df5
Packit 9f0df5
	if (c == CARD_ABSENT)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_COMM("Card removed");
Packit 9f0df5
	}
Packit 9f0df5
	else
Packit 9f0df5
		if (c == CARD_PRESENT)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_COMM("Card inserted");
Packit 9f0df5
		}
Packit 9f0df5
		else
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_COMM2("Unknown card movement: %d", c);
Packit 9f0df5
		}
Packit 9f0df5
	goto start;
Packit 9f0df5
Packit 9f0df5
sync:
Packit 9f0df5
	DEBUG_COMM("sync");
Packit 9f0df5
	if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
Packit 9f0df5
		return rv;
Packit 9f0df5
Packit 9f0df5
	if (c == CTRL_ACK)
Packit 9f0df5
		goto ack;
Packit 9f0df5
Packit 9f0df5
	if (c == CTRL_NAK)
Packit 9f0df5
		goto nak;
Packit 9f0df5
Packit 9f0df5
	DEBUG_CRITICAL2("Got 0x%02X instead of ACK/NAK", c);
Packit 9f0df5
	return STATUS_COMM_ERROR;
Packit 9f0df5
Packit 9f0df5
nak:
Packit 9f0df5
	DEBUG_COMM("nak");
Packit 9f0df5
	if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
Packit 9f0df5
		return rv;
Packit 9f0df5
Packit 9f0df5
	if (c != (SYNC ^ CTRL_NAK))
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
Packit 9f0df5
		return STATUS_COMM_ERROR;
Packit 9f0df5
	}
Packit 9f0df5
	else
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_COMM("NAK requested");
Packit 9f0df5
		return STATUS_COMM_NAK;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
ack:
Packit 9f0df5
	DEBUG_COMM("ack");
Packit 9f0df5
	/* normal CCID frame */
Packit 9f0df5
	if ((rv = get_bytes(reader_index, buffer, 5)) != STATUS_SUCCESS)
Packit 9f0df5
		return rv;
Packit 9f0df5
Packit 9f0df5
	/* total frame size */
Packit 9f0df5
	to_read = 10+dw2i(buffer, 1);
Packit 9f0df5
Packit 9f0df5
	if ((to_read < 10) || (to_read > (int)*length))
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_CRITICAL2("Wrong value for frame size: %d", to_read);
Packit 9f0df5
		return STATUS_COMM_ERROR;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	DEBUG_COMM2("frame size: %d", to_read);
Packit 9f0df5
	if ((rv = get_bytes(reader_index, buffer+5, to_read-5)) != STATUS_SUCCESS)
Packit 9f0df5
		return rv;
Packit 9f0df5
Packit 9f0df5
	DEBUG_XXD("frame: ", buffer, to_read);
Packit 9f0df5
Packit 9f0df5
	/* lrc */
Packit 9f0df5
	DEBUG_COMM("lrc");
Packit 9f0df5
	if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
Packit 9f0df5
		return rv;
Packit 9f0df5
Packit 9f0df5
	DEBUG_COMM2("lrc: 0x%02X", c);
Packit 9f0df5
	for (i=0; i
Packit 9f0df5
		c ^= buffer[i];
Packit 9f0df5
Packit 9f0df5
	if (c != (SYNC ^ CTRL_ACK))
Packit 9f0df5
		DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
Packit 9f0df5
Packit 9f0df5
	if (echo)
Packit 9f0df5
	{
Packit 9f0df5
		echo = FALSE;
Packit 9f0df5
		goto start;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* length of data read */
Packit 9f0df5
	*length = to_read;
Packit 9f0df5
Packit 9f0df5
	return STATUS_SUCCESS;
Packit 9f0df5
} /* ReadSerial */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *				get_bytes: get n bytes
Packit 9f0df5
 *
Packit 9f0df5
 *****************************************************************************/
Packit 9f0df5
int get_bytes(unsigned int reader_index, unsigned char *buffer, int length)
Packit 9f0df5
{
Packit 9f0df5
	int offset = serialDevice[reader_index].buffer_offset;
Packit 9f0df5
	int offset_last = serialDevice[reader_index].buffer_offset_last;
Packit 9f0df5
Packit 9f0df5
	DEBUG_COMM3("available: %d, needed: %d", offset_last-offset,
Packit 9f0df5
		length);
Packit 9f0df5
	/* enough data are available */
Packit 9f0df5
	if (offset + length <= offset_last)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_COMM("data available");
Packit 9f0df5
		memcpy(buffer, serialDevice[reader_index].buffer + offset, length);
Packit 9f0df5
		serialDevice[reader_index].buffer_offset += length;
Packit 9f0df5
	}
Packit 9f0df5
	else
Packit 9f0df5
	{
Packit 9f0df5
		int present, rv;
Packit 9f0df5
Packit 9f0df5
		/* copy available data */
Packit 9f0df5
		present = offset_last - offset;
Packit 9f0df5
Packit 9f0df5
		if (present > 0)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_COMM2("some data available: %d", present);
Packit 9f0df5
			memcpy(buffer, serialDevice[reader_index].buffer + offset,
Packit 9f0df5
				present);
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* get fresh data */
Packit 9f0df5
		DEBUG_COMM2("get more data: %d", length - present);
Packit 9f0df5
		rv = ReadChunk(reader_index, serialDevice[reader_index].buffer,
Packit 9f0df5
			sizeof(serialDevice[reader_index].buffer), length - present);
Packit 9f0df5
		if (rv < 0)
Packit 9f0df5
			return STATUS_COMM_ERROR;
Packit 9f0df5
Packit 9f0df5
		/* fill the buffer */
Packit 9f0df5
		memcpy(buffer + present, serialDevice[reader_index].buffer,
Packit 9f0df5
			length - present);
Packit 9f0df5
		serialDevice[reader_index].buffer_offset = length - present;
Packit 9f0df5
		serialDevice[reader_index].buffer_offset_last = rv;
Packit 9f0df5
		DEBUG_COMM3("offset: %d, last_offset: %d",
Packit 9f0df5
			serialDevice[reader_index].buffer_offset,
Packit 9f0df5
			serialDevice[reader_index].buffer_offset_last);
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	return STATUS_SUCCESS;
Packit 9f0df5
} /* get_bytes */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *				ReadChunk: read a minimum number of bytes
Packit 9f0df5
 *
Packit 9f0df5
 *****************************************************************************/
Packit 9f0df5
static int ReadChunk(unsigned int reader_index, unsigned char *buffer,
Packit 9f0df5
	int buffer_length, int min_length)
Packit 9f0df5
{
Packit 9f0df5
	int fd = serialDevice[reader_index].fd;
Packit 9f0df5
# ifndef S_SPLINT_S
Packit 9f0df5
	fd_set fdset;
Packit 9f0df5
# endif
Packit 9f0df5
	struct timeval t;
Packit 9f0df5
	int i, rv = 0;
Packit 9f0df5
	int already_read;
Packit 9f0df5
	char debug_header[] = "<- 123456 ";
Packit 9f0df5
Packit 9f0df5
	(void)snprintf(debug_header, sizeof(debug_header), "<- %06X ",
Packit 9f0df5
		reader_index);
Packit 9f0df5
Packit 9f0df5
	already_read = 0;
Packit 9f0df5
	while (already_read < min_length)
Packit 9f0df5
	{
Packit 9f0df5
		/* use select() to, eventually, timeout */
Packit 9f0df5
		FD_ZERO(&fdset);
Packit 9f0df5
		FD_SET(fd, &fdset);
Packit 9f0df5
		t.tv_sec = serialDevice[reader_index].ccid.readTimeout / 1000;
Packit 9f0df5
		t.tv_usec = (serialDevice[reader_index].ccid.readTimeout - t.tv_sec*1000)*1000;
Packit 9f0df5
Packit 9f0df5
		i = select(fd+1, &fdset, NULL, NULL, &t);
Packit 9f0df5
		if (i == -1)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_CRITICAL2("select: %s", strerror(errno));
Packit 9f0df5
			return -1;
Packit 9f0df5
		}
Packit 9f0df5
		else
Packit 9f0df5
			if (i == 0)
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_COMM2("Timeout! (%d ms)", serialDevice[reader_index].ccid.readTimeout);
Packit 9f0df5
				return -1;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
		rv = read(fd, buffer + already_read, buffer_length - already_read);
Packit 9f0df5
		if (rv < 0)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_COMM2("read error: %s", strerror(errno));
Packit 9f0df5
			return -1;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		DEBUG_XXD(debug_header, buffer + already_read, rv);
Packit 9f0df5
Packit 9f0df5
		already_read += rv;
Packit 9f0df5
		DEBUG_COMM3("read: %d, to read: %d", already_read,
Packit 9f0df5
			min_length);
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	return already_read;
Packit 9f0df5
} /* ReadChunk */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *				OpenSerial: open the port
Packit 9f0df5
 *
Packit 9f0df5
 *****************************************************************************/
Packit 9f0df5
status_t OpenSerial(unsigned int reader_index, int channel)
Packit 9f0df5
{
Packit 9f0df5
	char dev_name[FILENAME_MAX];
Packit 9f0df5
Packit 9f0df5
	DEBUG_COMM3("Reader index: %X, Channel: %d", reader_index, channel);
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * Conversion of old-style ifd-hanler 1.0 CHANNELID
Packit 9f0df5
	 */
Packit 9f0df5
	if (channel == 0x0103F8)
Packit 9f0df5
		channel = 1;
Packit 9f0df5
	else
Packit 9f0df5
		if (channel == 0x0102F8)
Packit 9f0df5
			channel = 2;
Packit 9f0df5
		else
Packit 9f0df5
			if (channel == 0x0103E8)
Packit 9f0df5
				channel = 3;
Packit 9f0df5
			else
Packit 9f0df5
				if (channel == 0x0102E8)
Packit 9f0df5
					channel = 4;
Packit 9f0df5
Packit 9f0df5
	if (channel < 0)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_CRITICAL2("wrong port number: %d", channel);
Packit 9f0df5
		return STATUS_UNSUCCESSFUL;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	(void)snprintf(dev_name, sizeof(dev_name), "/dev/pcsc/%d", channel);
Packit 9f0df5
Packit 9f0df5
	return OpenSerialByName(reader_index, dev_name);
Packit 9f0df5
} /* OpenSerial */
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *				set_ccid_descriptor: init ccid descriptor
Packit 9f0df5
 *				depending on reader type specified in device.
Packit 9f0df5
 *
Packit 9f0df5
 *				return: STATUS_UNSUCCESSFUL,
Packit 9f0df5
 *						STATUS_SUCCESS,
Packit 9f0df5
 *						-1 (Reader already used)
Packit 9f0df5
 *
Packit 9f0df5
 *****************************************************************************/
Packit 9f0df5
static status_t set_ccid_descriptor(unsigned int reader_index,
Packit 9f0df5
	const char *reader_name, const char *dev_name)
Packit 9f0df5
{
Packit 9f0df5
	int readerID;
Packit 9f0df5
	int i;
Packit 9f0df5
	int already_used = FALSE;
Packit 9f0df5
	static int previous_reader_index = -1;
Packit 9f0df5
Packit 9f0df5
	readerID = GEMPCTWIN;
Packit 9f0df5
	if (0 == strcasecmp(reader_name,"GemCorePOSPro"))
Packit 9f0df5
		readerID = GEMCOREPOSPRO;
Packit 9f0df5
	else if (0 == strcasecmp(reader_name,"GemCoreSIMPro"))
Packit 9f0df5
		readerID = GEMCORESIMPRO;
Packit 9f0df5
	else if (0 == strcasecmp(reader_name,"GemCoreSIMPro2"))
Packit 9f0df5
		readerID = GEMCORESIMPRO2;
Packit 9f0df5
	else if (0 == strcasecmp(reader_name,"GemPCPinPad"))
Packit 9f0df5
		readerID = GEMPCPINPAD;
Packit 9f0df5
	else if (0 == strcasecmp(reader_name,"SEC1210"))
Packit 9f0df5
		readerID = SEC1210;
Packit 9f0df5
Packit 9f0df5
	/* check if the same channel is not already used to manage multi-slots readers*/
Packit 9f0df5
	for (i = 0; i < CCID_DRIVER_MAX_READERS; i++)
Packit 9f0df5
	{
Packit 9f0df5
		if (serialDevice[i].device
Packit 9f0df5
			&& strcmp(serialDevice[i].device, dev_name) == 0)
Packit 9f0df5
		{
Packit 9f0df5
			already_used = TRUE;
Packit 9f0df5
Packit 9f0df5
			DEBUG_COMM2("%s already used. Multi-slot reader?", dev_name);
Packit 9f0df5
			break;
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* this reader is already managed by us */
Packit 9f0df5
	if (already_used)
Packit 9f0df5
	{
Packit 9f0df5
		if ((previous_reader_index != -1)
Packit 9f0df5
			&& serialDevice[previous_reader_index].device
Packit 9f0df5
			&& (strcmp(serialDevice[previous_reader_index].device, dev_name) == 0)
Packit 9f0df5
			&& serialDevice[previous_reader_index].ccid.bCurrentSlotIndex < serialDevice[previous_reader_index].ccid.bMaxSlotIndex)
Packit 9f0df5
		{
Packit 9f0df5
			/* we reuse the same device and the reader is multi-slot */
Packit 9f0df5
			serialDevice[reader_index] = serialDevice[previous_reader_index];
Packit 9f0df5
Packit 9f0df5
			*serialDevice[reader_index].nb_opened_slots += 1;
Packit 9f0df5
			serialDevice[reader_index].ccid.bCurrentSlotIndex++;
Packit 9f0df5
			serialDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT;
Packit 9f0df5
			DEBUG_INFO2("Opening slot: %d",
Packit 9f0df5
					serialDevice[reader_index].ccid.bCurrentSlotIndex);
Packit 9f0df5
			switch (readerID)
Packit 9f0df5
			{
Packit 9f0df5
				case GEMCOREPOSPRO:
Packit 9f0df5
				case GEMCORESIMPRO:
Packit 9f0df5
					{
Packit 9f0df5
						/* Allocate a memory buffer that will be
Packit 9f0df5
						 * released in CloseUSB() */
Packit 9f0df5
						void *ptr = malloc(sizeof SerialCustomDataRates);
Packit 9f0df5
						if (ptr)
Packit 9f0df5
						{
Packit 9f0df5
							memcpy(ptr, SerialCustomDataRates,
Packit 9f0df5
									sizeof SerialCustomDataRates);
Packit 9f0df5
						}
Packit 9f0df5
Packit 9f0df5
						serialDevice[reader_index].ccid.arrayOfSupportedDataRates = ptr;
Packit 9f0df5
					}
Packit 9f0df5
					serialDevice[reader_index].ccid.dwMaxDataRate = 125000;
Packit 9f0df5
					break;
Packit 9f0df5
Packit 9f0df5
				case SEC1210:
Packit 9f0df5
					serialDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL;
Packit 9f0df5
					serialDevice[reader_index].ccid.dwMaxDataRate = 826000;
Packit 9f0df5
					break;
Packit 9f0df5
Packit 9f0df5
				/* GemPC Twin or GemPC Card */
Packit 9f0df5
				default:
Packit 9f0df5
					serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialTwinDataRates;
Packit 9f0df5
					serialDevice[reader_index].ccid.dwMaxDataRate = 344086;
Packit 9f0df5
					break;
Packit 9f0df5
			}
Packit 9f0df5
			goto end;
Packit 9f0df5
		}
Packit 9f0df5
		else
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_CRITICAL2("Trying to open too many slots on %s", dev_name);
Packit 9f0df5
			return STATUS_UNSUCCESSFUL;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Common to all readers */
Packit 9f0df5
	serialDevice[reader_index].ccid.real_bSeq = 0;
Packit 9f0df5
	serialDevice[reader_index].ccid.pbSeq = &serialDevice[reader_index].ccid.real_bSeq;
Packit 9f0df5
	serialDevice[reader_index].real_nb_opened_slots = 1;
Packit 9f0df5
	serialDevice[reader_index].nb_opened_slots = &serialDevice[reader_index].real_nb_opened_slots;
Packit 9f0df5
	serialDevice[reader_index].ccid.bCurrentSlotIndex = 0;
Packit 9f0df5
Packit 9f0df5
	serialDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271;
Packit 9f0df5
	serialDevice[reader_index].ccid.dwMaxIFSD = 254;
Packit 9f0df5
	serialDevice[reader_index].ccid.dwFeatures = 0x00010230;
Packit 9f0df5
	serialDevice[reader_index].ccid.dwDefaultClock = 4000;
Packit 9f0df5
Packit 9f0df5
	serialDevice[reader_index].buffer_offset = 0;
Packit 9f0df5
	serialDevice[reader_index].buffer_offset_last = 0;
Packit 9f0df5
Packit 9f0df5
	serialDevice[reader_index].ccid.readerID = readerID;
Packit 9f0df5
	serialDevice[reader_index].ccid.bPINSupport = 0x0;
Packit 9f0df5
	serialDevice[reader_index].ccid.dwMaxDataRate = 344086;
Packit 9f0df5
	serialDevice[reader_index].ccid.bMaxSlotIndex = 0;
Packit 9f0df5
	serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialTwinDataRates;
Packit 9f0df5
	serialDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT;
Packit 9f0df5
	serialDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT;
Packit 9f0df5
	serialDevice[reader_index].ccid.bVoltageSupport = 0x07;	/* 1.8V, 3V and 5V */
Packit 9f0df5
	serialDevice[reader_index].ccid.gemalto_firmware_features = NULL;
Packit 9f0df5
#ifdef ENABLE_ZLP
Packit 9f0df5
	serialDevice[reader_index].ccid.zlp = FALSE;
Packit 9f0df5
#endif
Packit 9f0df5
	serialDevice[reader_index].echo = TRUE;
Packit 9f0df5
Packit 9f0df5
	/* change some values depending on the reader */
Packit 9f0df5
	switch (readerID)
Packit 9f0df5
	{
Packit 9f0df5
		case GEMCOREPOSPRO:
Packit 9f0df5
			serialDevice[reader_index].ccid.bMaxSlotIndex = 4;	/* 5 slots */
Packit 9f0df5
			serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialExtendedDataRates;
Packit 9f0df5
			serialDevice[reader_index].echo = FALSE;
Packit 9f0df5
			serialDevice[reader_index].ccid.dwMaxDataRate = 500000;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case GEMCORESIMPRO:
Packit 9f0df5
			serialDevice[reader_index].ccid.bMaxSlotIndex = 1; /* 2 slots */
Packit 9f0df5
			serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialExtendedDataRates;
Packit 9f0df5
			serialDevice[reader_index].echo = FALSE;
Packit 9f0df5
			serialDevice[reader_index].ccid.dwMaxDataRate = 500000;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case GEMCORESIMPRO2:
Packit 9f0df5
			serialDevice[reader_index].ccid.dwDefaultClock = 4800;
Packit 9f0df5
			serialDevice[reader_index].ccid.bMaxSlotIndex = 1; /* 2 slots */
Packit 9f0df5
			serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SIMPro2DataRates;
Packit 9f0df5
			serialDevice[reader_index].echo = FALSE;
Packit 9f0df5
			serialDevice[reader_index].ccid.dwMaxDataRate = 825806;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case GEMPCPINPAD:
Packit 9f0df5
			serialDevice[reader_index].ccid.bPINSupport = 0x03;
Packit 9f0df5
			serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialExtendedDataRates;
Packit 9f0df5
			serialDevice[reader_index].ccid.dwMaxDataRate = 500000;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case SEC1210:
Packit 9f0df5
			serialDevice[reader_index].ccid.dwFeatures = 0x000100B2;
Packit 9f0df5
			serialDevice[reader_index].ccid.dwDefaultClock = 4800;
Packit 9f0df5
			serialDevice[reader_index].ccid.dwMaxDataRate = 826000;
Packit 9f0df5
			serialDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL;
Packit 9f0df5
			serialDevice[reader_index].ccid.bMaxSlotIndex = 1;	/* 2 slots */
Packit 9f0df5
			serialDevice[reader_index].echo = FALSE;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
end:
Packit 9f0df5
	/* memorise the current reader_index so we can detect
Packit 9f0df5
	 * a new OpenSerialByName on a multi slot reader */
Packit 9f0df5
	previous_reader_index = reader_index;
Packit 9f0df5
Packit 9f0df5
	/* we just created a secondary slot on a multi-slot reader */
Packit 9f0df5
	if (already_used)
Packit 9f0df5
		return STATUS_SECONDARY_SLOT;
Packit 9f0df5
Packit 9f0df5
	return STATUS_SUCCESS;
Packit 9f0df5
} /* set_ccid_descriptor  */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *				OpenSerialByName: open the port
Packit 9f0df5
 *
Packit 9f0df5
 *****************************************************************************/
Packit 9f0df5
status_t OpenSerialByName(unsigned int reader_index, char *dev_name)
Packit 9f0df5
{
Packit 9f0df5
	struct termios current_termios;
Packit 9f0df5
	unsigned int reader = reader_index;
Packit 9f0df5
	/* 255 is MAX_DEVICENAME in pcscd.h */
Packit 9f0df5
	char reader_name[255] = "GemPCTwin";
Packit 9f0df5
	char *p;
Packit 9f0df5
	status_t ret;
Packit 9f0df5
Packit 9f0df5
	DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, dev_name);
Packit 9f0df5
Packit 9f0df5
	/* parse dev_name using the pattern "device:name" */
Packit 9f0df5
	p = strchr(dev_name, ':');
Packit 9f0df5
	if (p)
Packit 9f0df5
	{
Packit 9f0df5
		/* copy the second part of the string */
Packit 9f0df5
		strlcpy(reader_name, p+1, sizeof(reader_name));
Packit 9f0df5
Packit 9f0df5
		/* replace ':' by '\0' so that dev_name only contains the device name */
Packit 9f0df5
		*p = '\0';
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	ret = set_ccid_descriptor(reader_index, reader_name, dev_name);
Packit 9f0df5
	if (STATUS_UNSUCCESSFUL == ret)
Packit 9f0df5
		return STATUS_UNSUCCESSFUL;
Packit 9f0df5
Packit 9f0df5
	/* secondary slot so do not physically open the device */
Packit 9f0df5
	if (STATUS_SECONDARY_SLOT == ret)
Packit 9f0df5
		return STATUS_SUCCESS;
Packit 9f0df5
Packit 9f0df5
	serialDevice[reader].fd = open(dev_name, O_RDWR | O_NOCTTY);
Packit 9f0df5
Packit 9f0df5
	if (-1 == serialDevice[reader].fd)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_CRITICAL3("open %s: %s", dev_name, strerror(errno));
Packit 9f0df5
		return STATUS_UNSUCCESSFUL;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Set RTS signal to low to prevent the smart card reader
Packit 9f0df5
	 * from sending its plug and play string. */
Packit 9f0df5
	{
Packit 9f0df5
		int flags;
Packit 9f0df5
Packit 9f0df5
		if (ioctl(serialDevice[reader].fd, TIOCMGET, &flags) < 0)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_CRITICAL2("Get RS232 signals state failed: %s",
Packit 9f0df5
				strerror(errno));
Packit 9f0df5
		}
Packit 9f0df5
		else
Packit 9f0df5
		{
Packit 9f0df5
			flags &= ~TIOCM_RTS;
Packit 9f0df5
			if (ioctl(serialDevice[reader].fd, TIOCMSET, &flags) < 0)
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_CRITICAL2("Set RTS to low failed: %s", strerror(errno));
Packit 9f0df5
			}
Packit 9f0df5
			else
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_COMM("Plug-n-Play inhibition successful");
Packit 9f0df5
			}
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* set channel used */
Packit 9f0df5
	serialDevice[reader].device = strdup(dev_name);
Packit 9f0df5
Packit 9f0df5
	/* empty in and out serial buffers */
Packit 9f0df5
	if (tcflush(serialDevice[reader].fd, TCIOFLUSH))
Packit 9f0df5
			DEBUG_INFO2("tcflush() function error: %s", strerror(errno));
Packit 9f0df5
Packit 9f0df5
	/* get config attributes */
Packit 9f0df5
	if (tcgetattr(serialDevice[reader].fd, &current_termios) == -1)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_INFO2("tcgetattr() function error: %s", strerror(errno));
Packit 9f0df5
		(void)close(serialDevice[reader].fd);
Packit 9f0df5
		serialDevice[reader].fd = -1;
Packit 9f0df5
Packit 9f0df5
		return STATUS_UNSUCCESSFUL;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* IGNBRK: ignore BREAK condition on input
Packit 9f0df5
	 * IGNPAR: ignore framing errors and parity errors. */
Packit 9f0df5
	current_termios.c_iflag = IGNBRK | IGNPAR;
Packit 9f0df5
	current_termios.c_oflag = 0;	/* Raw output modes */
Packit 9f0df5
	/* CS8: 8-bits character size
Packit 9f0df5
	 * CSTOPB: set two stop bits
Packit 9f0df5
	 * CREAD: enable receiver
Packit 9f0df5
	 * CLOCAL: ignore modem control lines */
Packit 9f0df5
	current_termios.c_cflag = CS8 | CSTOPB | CREAD | CLOCAL;
Packit 9f0df5
Packit 9f0df5
	/* Do not echo characters because if you connect to a host it or your modem
Packit 9f0df5
	 * will echo characters for you.  Don't generate signals. */
Packit 9f0df5
	current_termios.c_lflag = 0;
Packit 9f0df5
Packit 9f0df5
	if (0 == strcasecmp(reader_name,"GemCoreSIMPro2"))
Packit 9f0df5
	{
Packit 9f0df5
		unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
Packit 9f0df5
		unsigned int old_timeout;
Packit 9f0df5
		RESPONSECODE r;
Packit 9f0df5
Packit 9f0df5
		/* Unless we resume from a stand-by condition, GemCoreSIMPro2
Packit 9f0df5
		 * starts at 9600 bauds, so let's first try this speed */
Packit 9f0df5
		/* set serial port speed to 9600 bauds */
Packit 9f0df5
		(void)cfsetspeed(&current_termios, B9600);
Packit 9f0df5
		DEBUG_INFO1("Set serial port baudrate to 9600 and correct configuration");
Packit 9f0df5
		if (tcsetattr(serialDevice[reader_index].fd, TCSANOW, &current_termios) == -1)
Packit 9f0df5
		{
Packit 9f0df5
			(void)close(serialDevice[reader_index].fd);
Packit 9f0df5
			serialDevice[reader_index].fd = -1;
Packit 9f0df5
			DEBUG_CRITICAL2("tcsetattr error: %s", strerror(errno));
Packit 9f0df5
Packit 9f0df5
			return STATUS_UNSUCCESSFUL;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* Test current speed issuing a CmdGetSlotStatus with a very
Packit 9f0df5
		 * short time out of 1 seconds */
Packit 9f0df5
		old_timeout = serialDevice[reader_index].ccid.readTimeout;
Packit 9f0df5
Packit 9f0df5
		serialDevice[reader_index].ccid.readTimeout = 1*1000;
Packit 9f0df5
		r = CmdGetSlotStatus(reader_index, pcbuffer);
Packit 9f0df5
Packit 9f0df5
		/* Restore default time out value */
Packit 9f0df5
		serialDevice[reader_index].ccid.readTimeout = old_timeout;
Packit 9f0df5
Packit 9f0df5
		if (IFD_SUCCESS == r)
Packit 9f0df5
		{
Packit 9f0df5
			/* We are at 9600 bauds, let's move to 115200 */
Packit 9f0df5
			unsigned char tx_buffer[] = { 0x01, 0x10, 0x20 };
Packit 9f0df5
			unsigned char rx_buffer[50];
Packit 9f0df5
			unsigned int rx_length = sizeof(rx_buffer);
Packit 9f0df5
Packit 9f0df5
			if (IFD_SUCCESS == CmdEscape(reader_index, tx_buffer,
Packit 9f0df5
				sizeof(tx_buffer), rx_buffer, &rx_length, 0))
Packit 9f0df5
			{
Packit 9f0df5
				/* Let the reader setup its new communication speed */
Packit 9f0df5
				(void)usleep(250*1000);
Packit 9f0df5
			}
Packit 9f0df5
			else
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_INFO1("CmdEscape to configure 115200 bauds failed");
Packit 9f0df5
			}
Packit 9f0df5
		}
Packit 9f0df5
		/* In case of a failure, reader is probably already at 115200
Packit 9f0df5
		 * bauds as code below assumes */
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* set serial port speed to 115200 bauds */
Packit 9f0df5
	(void)cfsetspeed(&current_termios, B115200);
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO1("Set serial port baudrate to 115200 and correct configuration");
Packit 9f0df5
	if (tcsetattr(serialDevice[reader].fd, TCSANOW, &current_termios) == -1)
Packit 9f0df5
	{
Packit 9f0df5
		(void)close(serialDevice[reader].fd);
Packit 9f0df5
		serialDevice[reader].fd = -1;
Packit 9f0df5
		DEBUG_INFO2("tcsetattr error: %s", strerror(errno));
Packit 9f0df5
Packit 9f0df5
		return STATUS_UNSUCCESSFUL;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* perform a command to be sure a Gemalto reader is connected
Packit 9f0df5
	 * get the reader firmware */
Packit 9f0df5
	{
Packit 9f0df5
		unsigned char tx_buffer[1];
Packit 9f0df5
		unsigned char rx_buffer[50];
Packit 9f0df5
		unsigned int rx_length = sizeof(rx_buffer);
Packit 9f0df5
Packit 9f0df5
		if (0 == strcasecmp(reader_name,"SEC1210"))
Packit 9f0df5
			tx_buffer[0] = 0x06; // unknown but supported command
Packit 9f0df5
		else
Packit 9f0df5
			tx_buffer[0] = 0x02; // get reader firmware
Packit 9f0df5
Packit 9f0df5
		/* 2 seconds timeout to not wait too long if no reader is connected */
Packit 9f0df5
		if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer),
Packit 9f0df5
			rx_buffer, &rx_length, 2*1000))
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_CRITICAL("Get firmware failed. Maybe the reader is not connected");
Packit 9f0df5
			(void)CloseSerial(reader_index);
Packit 9f0df5
			return STATUS_UNSUCCESSFUL;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		rx_buffer[rx_length] = '\0';
Packit 9f0df5
		DEBUG_INFO2("Firmware: %s", rx_buffer);
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* perform a command to configure GemPC Twin reader card movement
Packit 9f0df5
	 * notification to synchronous mode: the card movement is notified _after_
Packit 9f0df5
	 * the host command and _before_ the reader anwser */
Packit 9f0df5
	if (0 != strcasecmp(reader_name,"SEC1210"))
Packit 9f0df5
	{
Packit 9f0df5
		unsigned char tx_buffer[] = { 0x01, 0x01, 0x01};
Packit 9f0df5
		unsigned char rx_buffer[50];
Packit 9f0df5
		unsigned int rx_length = sizeof(rx_buffer);
Packit 9f0df5
Packit 9f0df5
		if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer),
Packit 9f0df5
			rx_buffer, &rx_length, 0))
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_CRITICAL("Change card movement notification failed.");
Packit 9f0df5
			(void)CloseSerial(reader_index);
Packit 9f0df5
			return STATUS_UNSUCCESSFUL;
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	serialDevice[reader_index].ccid.sIFD_serial_number = NULL;
Packit 9f0df5
	serialDevice[reader_index].ccid.sIFD_iManufacturer = NULL;
Packit 9f0df5
	serialDevice[reader_index].ccid.IFD_bcdDevice = 0;
Packit 9f0df5
Packit 9f0df5
	return STATUS_SUCCESS;
Packit 9f0df5
} /* OpenSerialByName */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *				CloseSerial: close the port
Packit 9f0df5
 *
Packit 9f0df5
 *****************************************************************************/
Packit 9f0df5
status_t CloseSerial(unsigned int reader_index)
Packit 9f0df5
{
Packit 9f0df5
	unsigned int reader = reader_index;
Packit 9f0df5
Packit 9f0df5
	/* device not opened */
Packit 9f0df5
	if (NULL == serialDevice[reader_index].device)
Packit 9f0df5
		return STATUS_UNSUCCESSFUL;
Packit 9f0df5
Packit 9f0df5
	DEBUG_COMM2("Closing serial device: %s", serialDevice[reader_index].device);
Packit 9f0df5
Packit 9f0df5
	/* Decrement number of opened slot */
Packit 9f0df5
	(*serialDevice[reader_index].nb_opened_slots)--;
Packit 9f0df5
Packit 9f0df5
	/* release the allocated ressources for the last slot only */
Packit 9f0df5
	if (0 == *serialDevice[reader_index].nb_opened_slots)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_COMM("Last slot closed. Release resources");
Packit 9f0df5
Packit 9f0df5
		(void)close(serialDevice[reader].fd);
Packit 9f0df5
		serialDevice[reader].fd = -1;
Packit 9f0df5
Packit 9f0df5
		free(serialDevice[reader].device);
Packit 9f0df5
		serialDevice[reader].device = NULL;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	return STATUS_SUCCESS;
Packit 9f0df5
} /* CloseSerial */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
/*****************************************************************************
Packit 9f0df5
 *
Packit 9f0df5
 *					get_ccid_descriptor
Packit 9f0df5
 *
Packit 9f0df5
 ****************************************************************************/
Packit 9f0df5
_ccid_descriptor *get_ccid_descriptor(unsigned int reader_index)
Packit 9f0df5
{
Packit 9f0df5
	return &serialDevice[reader_index].ccid;
Packit 9f0df5
} /* get_ccid_descriptor */
Packit 9f0df5
Packit 9f0df5