Blame src/ccid_serial.c

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