1/*
2 *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
3 *
4 *  @APPLE_LICENSE_HEADER_START@
5 *
6 *  This file contains Original Code and/or Modifications of Original Code
7 *  as defined in and that are subject to the Apple Public Source License
8 *  Version 2.0 (the 'License'). You may not use this file except in
9 *  compliance with the License. Please obtain a copy of the License at
10 *  http://www.opensource.apple.com/apsl/ and read it before using this
11 *  file.
12 *
13 *  The Original Code and all software distributed under the License are
14 *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 *  Please see the License for the specific language governing rights and
19 *  limitations under the License.
20 *
21 *  @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 *  readerfactory.c
26 *  SmartCardServices
27 */
28
29
30/******************************************************************
31
32	MUSCLE SmartCard Development ( http://www.linuxnet.com )
33	Title  : readerfactory.c
34	Package: pcsc lite
35	Author : David Corcoran
36	Date   : 7/27/99
37	License: Copyright (C) 1999 David Corcoran
38			<corcoran@linuxnet.com>
39	Purpose: This keeps track of a list of currently
40	available reader structures.
41
42$Id: readerfactory.c 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
43
44********************************************************************/
45
46#include "config.h"
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <unistd.h>
51#include <sys/types.h>
52#include <sys/stat.h>
53#include <sys/errno.h>
54#include <fcntl.h>
55
56#include "wintypes.h"
57#include "pcsclite.h"
58#include "ifdhandler.h"
59#include "debuglog.h"
60#include "thread_generic.h"
61#include "readerfactory.h"
62#include "dyn_generic.h"
63#include "sys_generic.h"
64#include "eventhandler.h"
65#include "ifdwrapper.h"
66#include "readerState.h"
67
68#include <security_utilities/debugging.h>
69
70/*
71 64 bit
72 */
73
74#include <mach/machine.h>
75#include <sys/sysctl.h>
76#include "configfile.h"
77
78static cpu_type_t architectureForPid(pid_t pid);
79
80#ifndef PCSCLITE_HP_BASE_PORT
81#define PCSCLITE_HP_BASE_PORT       0x200000
82#endif /* PCSCLITE_HP_BASE_PORT */
83
84static LONG RFLoadReader(PREADER_CONTEXT);
85static LONG RFUnBindFunctions(PREADER_CONTEXT);
86static LONG RFUnloadReader(PREADER_CONTEXT);
87
88static PREADER_CONTEXT sReadersContexts[PCSCLITE_MAX_READERS_CONTEXTS];
89static DWORD dwNumReadersContexts = 0;
90static DWORD lastLockID = 0;
91static PCSCLITE_MUTEX_T sReadersContextsLock = NULL;
92
93static int ReaderContextConstructor(PREADER_CONTEXT ctx, LPCSTR lpcReader,
94	DWORD dwPort, LPCSTR lpcLibrary, LPCSTR lpcDevice);
95static void ReaderContextDestructor(PREADER_CONTEXT ctx);
96static void ReaderContextFree(PREADER_CONTEXT ctx);
97static void ReaderContextClear(PREADER_CONTEXT ctx);
98static int ReaderContextInsert(PREADER_CONTEXT ctx);
99static int ReaderContextRemove(PREADER_CONTEXT ctx);
100static int ReaderContextCheckDuplicateReader(LPCSTR lpcReader, DWORD dwPort);
101static int ReaderSlotCount(PREADER_CONTEXT ctx);
102static BOOL ReaderDriverIsThreadSafe(PREADER_CONTEXT ctx, BOOL testSlot);
103static BOOL ReaderNameMatchForIndex(DWORD dwPort, LPCSTR lpcReader, int index);
104static void ReaderContextDuplicateSlot(PREADER_CONTEXT ctxBase, PREADER_CONTEXT ctxSlot, int slotNumber, BOOL baseIsThreadSafe);
105static int ReaderCheckForClone(PREADER_CONTEXT ctx, LPCSTR lpcReader,
106	DWORD dwPort, LPCSTR lpcLibrary);
107
108extern int DBUpdateReaders(const char *readerconf);
109
110LONG RFAllocateReaderSpace()
111{
112	int i;
113
114	sReadersContextsLock = (PCSCLITE_MUTEX_T) malloc(sizeof(PCSCLITE_MUTEX));
115	SYS_MutexInit(sReadersContextsLock);
116
117	/*
118	 * Allocate each reader structure
119	 */
120	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
121		sReadersContexts[i] = (PREADER_CONTEXT) calloc(1, sizeof(READER_CONTEXT));
122
123	/*
124	 * Create public event structures
125	 */
126	return EHInitializeEventStructures();
127}
128
129LONG RFAddReader(LPSTR lpcReader, DWORD dwPort, LPSTR lpcLibrary, LPSTR lpcDevice)
130{
131	int slotCount;
132	LONG rv = SCARD_E_NO_MEMORY;
133	int slot;
134	PREADER_CONTEXT baseContext = NULL;
135
136	if ((lpcReader == NULL) || (lpcLibrary == NULL) || (lpcDevice == NULL))
137		return SCARD_E_INVALID_VALUE;
138
139	/* Reader name too long? */
140	if (strlen(lpcReader) >= MAX_READERNAME)
141	{
142		Log3(PCSC_LOG_ERROR, "Reader name too long: %d chars instead of max %d",
143			strlen(lpcReader), MAX_READERNAME);
144		return SCARD_E_INVALID_VALUE;
145	}
146
147	/* Library name too long? */
148	if (strlen(lpcLibrary) >= MAX_LIBNAME)
149	{
150		Log3(PCSC_LOG_ERROR, "Library name too long: %d chars instead of max %d",
151			strlen(lpcLibrary), MAX_LIBNAME);
152		return SCARD_E_INVALID_VALUE;
153	}
154
155	/* Device name too long? */
156	if (strlen(lpcDevice) >= MAX_DEVICENAME)
157	{
158		Log3(PCSC_LOG_ERROR, "Device name too long: %d chars instead of max %d",
159			strlen(lpcDevice), MAX_DEVICENAME);
160		return SCARD_E_INVALID_VALUE;
161	}
162
163	rv = ReaderContextCheckDuplicateReader(lpcReader, dwPort);
164	if (rv)
165		return rv;
166
167	// Make sure we have an empty slot to put the reader structure
168	rv = ReaderContextInsert(NULL);
169	if (rv != SCARD_S_SUCCESS)
170		return rv;
171
172	// Allocate a temporary reader context struct
173	baseContext = (PREADER_CONTEXT) calloc(1, sizeof(READER_CONTEXT));
174
175	rv = ReaderContextConstructor(baseContext, lpcReader, dwPort, lpcLibrary, lpcDevice);
176	if (rv != SCARD_S_SUCCESS)
177		goto xit;
178
179	rv = ReaderCheckForClone(baseContext, lpcReader, dwPort, lpcLibrary);
180	if (rv != SCARD_S_SUCCESS)
181		goto xit;
182
183	rv = RFInitializeReader(baseContext);
184	if (rv != SCARD_S_SUCCESS)
185		goto xit;
186
187	rv = ReaderContextInsert(baseContext);
188	if (rv != SCARD_S_SUCCESS)
189		goto xit;
190
191	rv = EHSpawnEventHandler(baseContext);
192	if (rv != SCARD_S_SUCCESS)
193		goto xit;
194
195	slotCount = ReaderSlotCount(baseContext);
196	if (slotCount <= 1)
197		return SCARD_S_SUCCESS;
198
199	/*
200	 * Check the number of slots and create a different
201	 * structure for each one accordingly
202	 */
203
204	BOOL baseIsThreadSafe = ReaderDriverIsThreadSafe(baseContext, 1);
205
206	for (slot = 1; slot < slotCount; slot++)
207	{
208		// Make sure we have an empty slot to put the reader structure
209		// If not, we remove the whole reader
210		rv = ReaderContextInsert(NULL);
211		if (rv != SCARD_S_SUCCESS)
212		{
213			rv = RFRemoveReader(lpcReader, dwPort);
214			return rv;
215		}
216
217		// Allocate a temporary reader context struct
218		PREADER_CONTEXT ctxSlot = (PREADER_CONTEXT) calloc(1, sizeof(READER_CONTEXT));
219
220		rv = ReaderContextConstructor(ctxSlot, lpcReader, dwPort, lpcLibrary, lpcDevice);
221		if (rv != SCARD_S_SUCCESS)
222		{
223			ReaderContextDestructor(ctxSlot);
224			free(ctxSlot);
225			return rv;
226		}
227
228		ReaderContextDuplicateSlot(baseContext, ctxSlot, slot, baseIsThreadSafe);
229
230		rv = RFInitializeReader(ctxSlot);
231		if (rv != SCARD_S_SUCCESS)
232		{
233			Log2(PCSC_LOG_ERROR, "%s init failed.", lpcReader);
234			ReaderContextDestructor(ctxSlot);
235			free(ctxSlot);
236			return rv;
237		}
238
239		rv = ReaderContextInsert(ctxSlot);
240		if (rv != SCARD_S_SUCCESS)
241			return rv;
242
243		rv = EHSpawnEventHandler(ctxSlot);
244		if (rv != SCARD_S_SUCCESS)
245			return rv;
246	}
247
248xit:
249	if (rv != SCARD_S_SUCCESS)
250	{
251		// Cannot connect to reader, so exit gracefully
252		Log3(PCSC_LOG_ERROR, "RFAddReader: %s init failed: %d", lpcReader, rv);
253		ReaderContextDestructor(baseContext);
254		free(baseContext);
255	}
256
257	return rv;
258}
259
260LONG RFRemoveReader(LPSTR lpcReader, DWORD dwPort)
261{
262	LONG rv;
263	PREADER_CONTEXT tmpContext = NULL;
264
265	if (lpcReader == 0)
266		return SCARD_E_INVALID_VALUE;
267
268	secdebug("pcscd", "RFRemoveReader: removing %s", lpcReader);
269	while ((rv = RFReaderInfoNamePort(dwPort, lpcReader, &tmpContext)) == SCARD_S_SUCCESS)
270	{
271		// Try to destroy the thread
272		rv = EHDestroyEventHandler(tmpContext);
273
274		rv = RFUnInitializeReader(tmpContext);
275		if (rv != SCARD_S_SUCCESS)
276			return rv;
277
278		ReaderContextRemove(tmpContext);
279	}
280
281	return SCARD_S_SUCCESS;
282}
283
284LONG RFSetReaderName(PREADER_CONTEXT rContext, LPCSTR readerName,
285	LPCSTR libraryName, DWORD dwPort, DWORD dwSlot)
286{
287	LONG parent = -1;	/* reader number of the parent of the clone */
288	DWORD valueLength;
289	int currentDigit = -1;
290	int supportedChannels = 0;
291	int usedDigits[PCSCLITE_MAX_READERS_CONTEXTS] = {0,};
292	int i;
293
294	if ((0 == dwSlot) && (dwNumReadersContexts != 0))
295	{
296		for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
297		{
298			if (sReadersContexts[i] == NULL)
299				continue;
300			if ((sReadersContexts[i])->vHandle != 0)
301			{
302				if (strcmp((sReadersContexts[i])->lpcLibrary, libraryName) == 0)
303				{
304					UCHAR tagValue[1];
305					LONG ret;
306
307					/*
308					 * Ask the driver if it supports multiple channels
309					 */
310					valueLength = sizeof(tagValue);
311					ret = IFDGetCapabilities((sReadersContexts[i]),
312						TAG_IFD_SIMULTANEOUS_ACCESS,
313						&valueLength, tagValue);
314
315					if ((ret == IFD_SUCCESS) && (valueLength == 1) &&
316						(tagValue[0] > 1))
317					{
318						supportedChannels = tagValue[0];
319						Log2(PCSC_LOG_INFO,
320							"Support %d simultaneous readers", tagValue[0]);
321					}
322					else
323						supportedChannels = 1;
324
325					/*
326					 * Check to see if it is a hotplug reader and
327					 * different
328					 */
329					if (((((sReadersContexts[i])->dwPort & 0xFFFF0000) ==
330							PCSCLITE_HP_BASE_PORT)
331						&& ((sReadersContexts[i])->dwPort != dwPort))
332						|| (supportedChannels > 1))
333					{
334						char *lpcReader = sReadersContexts[i]->lpcReader;
335
336						/*
337						 * tells the caller who the parent of this
338						 * clone is so it can use it's shared
339						 * resources like mutex/etc.
340						 */
341						parent = i;
342
343						/*
344						 * If the same reader already exists and it is
345						 * hotplug then we must look for others and
346						 * enumerate the readername
347						 */
348						currentDigit = strtol(lpcReader + strlen(lpcReader) - 5, NULL, 16);
349
350						/*
351						 * This spot is taken
352						 */
353						usedDigits[currentDigit] = 1;
354					}
355				}
356			}
357		}
358
359	}
360
361	/* default value */
362	i = 0;
363
364	/* Other identical readers exist on the same bus */
365	if (currentDigit != -1)
366	{
367		for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
368		{
369			/* get the first free digit */
370			if (usedDigits[i] == 0)
371				break;
372		}
373
374		if (i == PCSCLITE_MAX_READERS_CONTEXTS)
375		{
376			Log2(PCSC_LOG_ERROR, "Max number of readers reached: %d", PCSCLITE_MAX_READERS_CONTEXTS);
377			return -2;
378		}
379
380		if (i >= supportedChannels)
381		{
382			Log3(PCSC_LOG_ERROR, "Driver %s does not support more than "
383				"%d reader(s). Maybe the driver should support "
384				"TAG_IFD_SIMULTANEOUS_ACCESS", libraryName, supportedChannels);
385			return -2;
386		}
387	}
388
389	sprintf(rContext->lpcReader, "%s %02X %02X", readerName, i, dwSlot);
390
391	/*
392	 * Set the slot in 0xDDDDCCCC
393	 */
394	rContext->dwSlot = (i << 16) + dwSlot;
395
396	return parent;
397}
398
399LONG RFReaderInfo(LPSTR lpcReader, PREADER_CONTEXT * sReader)
400{
401	int i;
402	LONG rv = SCARD_E_UNKNOWN_READER;
403
404	if (lpcReader == 0)
405		return SCARD_E_UNKNOWN_READER;
406
407	SYS_MutexLock(sReadersContextsLock);
408	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
409	{
410		if ((sReadersContexts[i]!=NULL) && ((sReadersContexts[i])->vHandle != 0))
411		{
412			if (strcmp(lpcReader, (sReadersContexts[i])->lpcReader) == 0)
413			{
414				*sReader = sReadersContexts[i];
415				rv = SCARD_S_SUCCESS;
416				break;
417			}
418		}
419	}
420	SYS_MutexUnLock(sReadersContextsLock);
421
422	return rv;
423}
424
425LONG RFReaderInfoNamePort(DWORD dwPort, LPSTR lpcReader,
426	PREADER_CONTEXT * sReader)
427{
428	int ix;
429	LONG rv = SCARD_E_INVALID_VALUE;
430
431	SYS_MutexLock(sReadersContextsLock);
432	for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
433	{
434		if ((sReadersContexts[ix]!=NULL) && ((sReadersContexts[ix])->vHandle != 0) &&
435			ReaderNameMatchForIndex(dwPort, lpcReader, ix))
436			{
437				*sReader = sReadersContexts[ix];
438				rv = SCARD_S_SUCCESS;
439				break;
440			}
441	}
442	SYS_MutexUnLock(sReadersContextsLock);
443
444	return rv;
445}
446
447LONG RFReaderInfoById(DWORD dwIdentity, PREADER_CONTEXT * sReader)
448{
449	int i;
450	LONG rv = SCARD_E_INVALID_VALUE;
451
452	/*
453	 * Strip off the lower nibble and get the identity
454	 */
455	dwIdentity = dwIdentity >> (sizeof(DWORD) / 2) * 8;
456	dwIdentity = dwIdentity << (sizeof(DWORD) / 2) * 8;
457
458	SYS_MutexLock(sReadersContextsLock);
459	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
460	{
461		if ((sReadersContexts[i]!=NULL) && (dwIdentity == (sReadersContexts[i])->dwIdentity))
462		{
463			*sReader = sReadersContexts[i];
464			rv = SCARD_S_SUCCESS;
465			break;
466		}
467	}
468	SYS_MutexUnLock(sReadersContextsLock);
469
470	return rv;
471}
472
473static LONG RFLoadReader(PREADER_CONTEXT rContext)
474{
475	if (rContext->vHandle != 0)
476	{
477		Log1(PCSC_LOG_ERROR, "Warning library pointer not NULL");
478		/*
479		 * Another reader exists with this library loaded
480		 */
481		return SCARD_S_SUCCESS;
482	}
483
484	return DYN_LoadLibrary(&rContext->vHandle, rContext->lpcLibrary);
485}
486
487LONG RFBindFunctions(PREADER_CONTEXT rContext)
488{
489	int rv1, rv2, rv3;
490	void *f;
491
492	/*
493	 * Use this function as a dummy to determine the IFD Handler version
494	 * type  1.0/2.0/3.0.  Suppress error messaging since it can't be 1.0,
495	 * 2.0 and 3.0.
496	 */
497
498	Log1(PCSC_LOG_INFO, "Binding driver functions");
499
500//	DebugLogSuppress(DEBUGLOG_IGNORE_ENTRIES);
501
502	rv1 = DYN_GetAddress(rContext->vHandle, &f, "IO_Create_Channel");
503	rv2 = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannel");
504	rv3 = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannelByName");
505
506//	DebugLogSuppress(DEBUGLOG_LOG_ENTRIES);
507
508	if (rv1 != SCARD_S_SUCCESS && rv2 != SCARD_S_SUCCESS && rv3 != SCARD_S_SUCCESS)
509	{
510		/*
511		 * Neither version of the IFD Handler was found - exit
512		 */
513		Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing");
514
515		exit(1);
516	} else if (rv1 == SCARD_S_SUCCESS)
517	{
518		/*
519		 * Ifd Handler 1.0 found
520		 */
521		rContext->dwVersion = IFD_HVERSION_1_0;
522	} else if (rv3 == SCARD_S_SUCCESS)
523	{
524		/*
525		 * Ifd Handler 3.0 found
526		 */
527		rContext->dwVersion = IFD_HVERSION_3_0;
528	}
529	else
530	{
531		/*
532		 * Ifd Handler 2.0 found
533		 */
534		rContext->dwVersion = IFD_HVERSION_2_0;
535	}
536
537	/*
538	 * The following binds version 1.0 of the IFD Handler specs
539	 */
540
541	if (rContext->dwVersion == IFD_HVERSION_1_0)
542	{
543		Log1(PCSC_LOG_INFO, "Loading IFD Handler 1.0");
544
545#define GET_ADDRESS_OPTIONALv1(field, function, code) \
546{ \
547	void *f1 = NULL; \
548	if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f1, "IFD_" #function)) \
549	{ \
550		code \
551	} \
552	rContext->psFunctions.psFunctions_v1.pvf ## field = f1; \
553}
554
555#define GET_ADDRESSv1(field, function) \
556	GET_ADDRESS_OPTIONALv1(field, function, \
557		Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #function ); \
558		exit(1); )
559
560		DYN_GetAddress(rContext->vHandle, &f, "IO_Create_Channel");
561		rContext->psFunctions.psFunctions_v1.pvfCreateChannel = f;
562
563		if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f,
564			"IO_Close_Channel"))
565		{
566			Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing");
567			exit(1);
568		}
569		rContext->psFunctions.psFunctions_v1.pvfCloseChannel = f;
570
571		GET_ADDRESSv1(GetCapabilities, Get_Capabilities)
572		GET_ADDRESSv1(SetCapabilities, Set_Capabilities)
573		GET_ADDRESSv1(PowerICC, Power_ICC)
574		GET_ADDRESSv1(TransmitToICC, Transmit_to_ICC)
575		GET_ADDRESSv1(ICCPresence, Is_ICC_Present)
576
577		GET_ADDRESS_OPTIONALv1(SetProtocolParameters, Set_Protocol_Parameters, )
578	}
579	else if (rContext->dwVersion == IFD_HVERSION_2_0)
580	{
581		/*
582		 * The following binds version 2.0 of the IFD Handler specs
583		 */
584
585#define GET_ADDRESS_OPTIONALv2(s, code) \
586{ \
587	void *f1 = NULL; \
588	if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s)) \
589	{ \
590		code \
591	} \
592	rContext->psFunctions.psFunctions_v2.pvf ## s = f1; \
593}
594
595#define GET_ADDRESSv2(s) \
596	GET_ADDRESS_OPTIONALv2(s, \
597		Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #s ); \
598		exit(1); )
599
600		Log1(PCSC_LOG_INFO, "Loading IFD Handler 2.0");
601
602		GET_ADDRESSv2(CreateChannel)
603		GET_ADDRESSv2(CloseChannel)
604		GET_ADDRESSv2(GetCapabilities)
605		GET_ADDRESSv2(SetCapabilities)
606		GET_ADDRESSv2(PowerICC)
607		GET_ADDRESSv2(TransmitToICC)
608		GET_ADDRESSv2(ICCPresence)
609		GET_ADDRESS_OPTIONALv2(SetProtocolParameters, )
610
611		GET_ADDRESSv2(Control)
612	}
613	else if (rContext->dwVersion == IFD_HVERSION_3_0)
614	{
615		/*
616		 * The following binds version 3.0 of the IFD Handler specs
617		 */
618
619#define GET_ADDRESS_OPTIONALv3(s, code) \
620{ \
621	void *f1 = NULL; \
622	if (SCARD_S_SUCCESS != DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s)) \
623	{ \
624		code \
625	} \
626	rContext->psFunctions.psFunctions_v3.pvf ## s = f1; \
627}
628
629#define GET_ADDRESSv3(s) \
630	GET_ADDRESS_OPTIONALv3(s, \
631		Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #s ); \
632		exit(1); )
633
634		Log1(PCSC_LOG_INFO, "Loading IFD Handler 3.0");
635
636		GET_ADDRESSv2(CreateChannel)
637		GET_ADDRESSv2(CloseChannel)
638		GET_ADDRESSv2(GetCapabilities)
639		GET_ADDRESSv2(SetCapabilities)
640		GET_ADDRESSv2(PowerICC)
641		GET_ADDRESSv2(TransmitToICC)
642		GET_ADDRESSv2(ICCPresence)
643		GET_ADDRESS_OPTIONALv2(SetProtocolParameters, )
644
645		GET_ADDRESSv3(CreateChannelByName)
646		GET_ADDRESSv3(Control)
647	}
648	else
649	{
650		/*
651		 * Who knows what could have happenned for it to get here.
652		 */
653		Log1(PCSC_LOG_CRITICAL, "IFD Handler not 1.0/2.0 or 3.0");
654		exit(1);
655	}
656
657	return SCARD_S_SUCCESS;
658}
659
660static LONG RFUnBindFunctions(PREADER_CONTEXT rContext)
661{
662	/*
663	 * Zero out everything
664	 */
665
666	Log1(PCSC_LOG_INFO, "Unbinding driver functions");
667	memset(&rContext->psFunctions, 0, sizeof(rContext->psFunctions));
668
669	return SCARD_S_SUCCESS;
670}
671
672static LONG RFUnloadReader(PREADER_CONTEXT rContext)
673{
674	/*
675	 * Make sure no one else is using this library
676	 */
677
678		Log1(PCSC_LOG_INFO, "Unloading reader driver.");
679	if (*rContext->pdwFeeds == 1)
680	{
681		Log1(PCSC_LOG_INFO, "--- closing dynamic library");
682		DYN_CloseLibrary(&rContext->vHandle);
683	}
684
685	rContext->vHandle = 0;
686
687	return SCARD_S_SUCCESS;
688}
689
690LONG RFCheckSharing(DWORD hCard)
691{
692	LONG rv;
693	PREADER_CONTEXT rContext = NULL;
694
695	rv = RFReaderInfoById(hCard, &rContext);
696
697	if (rv != SCARD_S_SUCCESS)
698		return rv;
699
700	if (rContext->dwLockId == 0 || rContext->dwLockId == hCard)
701		return SCARD_S_SUCCESS;
702	else
703	{
704		secdebug("pcscd", "RFCheckSharing: sharing violation, dwLockId: 0x%02X", rContext->dwLockId);
705		return SCARD_E_SHARING_VIOLATION;
706	}
707}
708
709LONG RFLockSharing(DWORD hCard)
710{
711	PREADER_CONTEXT rContext = NULL;
712
713	RFReaderInfoById(hCard, &rContext);
714
715	if (RFCheckSharing(hCard) == SCARD_S_SUCCESS)
716	{
717		EHSetSharingEvent(rContext, 1);
718		rContext->dwLockId = hCard;
719	}
720	else
721		return SCARD_E_SHARING_VIOLATION;
722
723	return SCARD_S_SUCCESS;
724}
725
726LONG RFUnlockSharing(DWORD hCard)
727{
728	PREADER_CONTEXT rContext = NULL;
729	LONG rv;
730
731	rv = RFReaderInfoById(hCard, &rContext);
732	if (rv != SCARD_S_SUCCESS)
733		return rv;
734
735	rv = RFCheckSharing(hCard);
736	if (rv != SCARD_S_SUCCESS)
737		return rv;
738
739	EHSetSharingEvent(rContext, 0);
740	rContext->dwLockId = 0;
741
742	return SCARD_S_SUCCESS;
743}
744
745LONG RFUnblockContext(SCARDCONTEXT hContext)
746{
747	int i;
748
749	SYS_MutexLock(sReadersContextsLock);
750	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
751		if (sReadersContexts[i])
752			(sReadersContexts[i])->dwBlockStatus = hContext;
753	SYS_MutexUnLock(sReadersContextsLock);
754
755	return SCARD_S_SUCCESS;
756}
757
758LONG RFUnblockReader(PREADER_CONTEXT rContext)
759{
760	rContext->dwBlockStatus = BLOCK_STATUS_RESUME;
761	return SCARD_S_SUCCESS;
762}
763
764LONG RFInitializeReader(PREADER_CONTEXT rContext)
765{
766	LONG rv;
767
768	/*
769	 * Spawn the event handler thread
770	 */
771	Log3(PCSC_LOG_INFO, "Attempting startup of %s using %s",
772		rContext->lpcReader, rContext->lpcLibrary);
773
774  /******************************************/
775	/*
776	 * This section loads the library
777	 */
778  /******************************************/
779	rv = RFLoadReader(rContext);
780	if (rv != SCARD_S_SUCCESS)
781	{
782		Log2(PCSC_LOG_ERROR, "RFLoadReader failed: %X", rv);
783		return rv;
784	}
785
786  /*******************************************/
787	/*
788	 * This section binds the functions
789	 */
790  /*******************************************/
791	rv = RFBindFunctions(rContext);
792
793	if (rv != SCARD_S_SUCCESS)
794	{
795		Log2(PCSC_LOG_ERROR, "RFBindFunctions failed: %X", rv);
796		RFUnloadReader(rContext);
797		return rv;
798	}
799
800  /*******************************************/
801	/*
802	 * This section tries to open the port
803	 */
804  /*******************************************/
805
806	rv = IFDOpenIFD(rContext);
807
808	if (rv != IFD_SUCCESS)
809	{
810		Log3(PCSC_LOG_CRITICAL, "Open Port %X Failed (%s)",
811			rContext->dwPort, rContext->lpcDevice);
812		RFUnBindFunctions(rContext);
813		RFUnloadReader(rContext);
814		return SCARD_E_INVALID_TARGET;
815	}
816
817	return SCARD_S_SUCCESS;
818}
819
820LONG RFUnInitializeReader(PREADER_CONTEXT rContext)
821{
822	Log2(PCSC_LOG_INFO, "Attempting shutdown of %s.",
823		rContext->lpcReader);
824
825	/*
826	 * Close the port, unbind the functions, and unload the library
827	 */
828
829	/*
830	 * If the reader is getting uninitialized then it is being unplugged
831	 * so I can't send a IFDPowerICC call to it
832	 *
833	 * IFDPowerICC( rContext, IFD_POWER_DOWN, Atr, &AtrLen );
834	 */
835	IFDCloseIFD(rContext);
836	RFUnBindFunctions(rContext);
837	RFUnloadReader(rContext);
838
839	return SCARD_S_SUCCESS;
840}
841
842SCARDHANDLE RFCreateReaderHandle(PREADER_CONTEXT rContext)
843{
844	USHORT randHandle;
845
846	/*
847	 * Create a random handle with 16 bits check to see if it already is
848	 * used.
849	 */
850	randHandle = SYS_Random(SYS_GetSeed(), 10, 65000);
851
852	while (1)
853	{
854		int i;
855
856		SYS_MutexLock(sReadersContextsLock);
857		for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
858		{
859			if ((sReadersContexts[i]!=NULL) && ((sReadersContexts[i])->vHandle != 0))
860			{
861				int j;
862
863				for (j = 0; j < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; j++)
864				{
865					if ((rContext->dwIdentity + randHandle) ==
866						(sReadersContexts[i])->psHandles[j].hCard)
867					{
868						/*
869						 * Get a new handle and loop again
870						 */
871						randHandle = SYS_Random(randHandle, 10, 65000);
872						continue;
873					}
874				}
875			}
876		}
877		SYS_MutexUnLock(sReadersContextsLock);
878
879		/*
880		 * Once the for loop is completed w/o restart a good handle was
881		 * found and the loop can be exited.
882		 */
883
884		if (i == PCSCLITE_MAX_READERS_CONTEXTS)
885			break;
886	}
887
888	return rContext->dwIdentity + randHandle;
889}
890
891LONG RFFindReaderHandle(SCARDHANDLE hCard)
892{
893	int i;
894	LONG rv = SCARD_E_INVALID_HANDLE;
895
896	SYS_MutexLock(sReadersContextsLock);
897	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
898	{
899		if ((sReadersContexts[i]!=NULL) && ((sReadersContexts[i])->vHandle != 0))
900		{
901			int j;
902
903			for (j = 0; j < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; j++)
904			{
905				if (hCard == (sReadersContexts[i])->psHandles[j].hCard)
906				{
907					rv = SCARD_S_SUCCESS;
908					goto xit;
909				}
910			}
911		}
912	}
913xit:
914	SYS_MutexUnLock(sReadersContextsLock);
915
916	return rv;
917}
918
919LONG RFDestroyReaderHandle(SCARDHANDLE hCard)
920{
921	return SCARD_S_SUCCESS;
922}
923
924LONG RFAddReaderHandle(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
925{
926	int i;
927
928	for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
929	{
930		if (rContext->psHandles[i].hCard == 0)
931		{
932			rContext->psHandles[i].hCard = hCard;
933			rContext->psHandles[i].dwEventStatus = 0;
934			break;
935		}
936	}
937
938	if (i == PCSCLITE_MAX_READER_CONTEXT_CHANNELS)
939		/* List is full */
940		return SCARD_E_INSUFFICIENT_BUFFER;
941
942	return SCARD_S_SUCCESS;
943}
944
945LONG RFRemoveReaderHandle(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
946{
947	int i;
948
949	for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
950	{
951		if (rContext->psHandles[i].hCard == hCard)
952		{
953			rContext->psHandles[i].hCard = 0;
954			rContext->psHandles[i].dwEventStatus = 0;
955			break;
956		}
957	}
958
959	if (i == PCSCLITE_MAX_READER_CONTEXT_CHANNELS)
960		/* Not Found */
961		return SCARD_E_INVALID_HANDLE;
962
963	return SCARD_S_SUCCESS;
964}
965
966LONG RFSetReaderEventState(PREADER_CONTEXT rContext, DWORD dwEvent)
967{
968	int i;
969
970	/*
971	 * Set all the handles for that reader to the event
972	 */
973	for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
974	{
975		if (rContext->psHandles[i].hCard != 0)
976			rContext->psHandles[i].dwEventStatus = dwEvent;
977	}
978
979	return SCARD_S_SUCCESS;
980}
981
982LONG RFCheckReaderEventState(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
983{
984	int i;
985
986	for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
987	{
988		if (rContext->psHandles[i].hCard == hCard)
989		{
990			if (rContext->psHandles[i].dwEventStatus == SCARD_REMOVED)
991				return SCARD_W_REMOVED_CARD;
992			else
993			{
994				if (rContext->psHandles[i].dwEventStatus == SCARD_RESET)
995					return SCARD_W_RESET_CARD;
996				else
997				{
998					if (rContext->psHandles[i].dwEventStatus == 0)
999						return SCARD_S_SUCCESS;
1000					else
1001						return SCARD_E_INVALID_VALUE;
1002				}
1003			}
1004		}
1005	}
1006
1007	return SCARD_E_INVALID_HANDLE;
1008}
1009
1010LONG RFClearReaderEventState(PREADER_CONTEXT rContext, SCARDHANDLE hCard)
1011{
1012	int i;
1013
1014	for (i = 0; i < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; i++)
1015	{
1016		if (rContext->psHandles[i].hCard == hCard)
1017			rContext->psHandles[i].dwEventStatus = 0;
1018	}
1019
1020	if (i == PCSCLITE_MAX_READER_CONTEXT_CHANNELS)
1021		/* Not Found */
1022		return SCARD_E_INVALID_HANDLE;
1023
1024	return SCARD_S_SUCCESS;
1025}
1026
1027LONG RFCheckReaderStatus(PREADER_CONTEXT rContext)
1028{
1029	LONG rx = 0;
1030	rx = ((rContext == NULL) || (rContext->readerState == NULL) ||
1031		(SharedReaderState_State(rContext->readerState) & SCARD_UNKNOWN))?SCARD_E_READER_UNAVAILABLE:SCARD_S_SUCCESS;
1032	return rx;
1033}
1034
1035void RFCleanupReaders(int shouldExit)
1036{
1037	int i;
1038
1039	Log1(PCSC_LOG_INFO, "entering cleaning function");
1040	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1041	{
1042		if ((sReadersContexts[i]!=NULL) && (sReadersContexts[i]->vHandle != 0))
1043		{
1044			LONG rv;
1045			char lpcStripReader[MAX_READERNAME];
1046
1047			Log2(PCSC_LOG_INFO, "Stopping reader: %s",
1048				sReadersContexts[i]->lpcReader);
1049
1050			strncpy(lpcStripReader, (sReadersContexts[i])->lpcReader,
1051				sizeof(lpcStripReader));
1052			/*
1053			 * strip the 6 last char ' 00 00'
1054			 */
1055			lpcStripReader[strlen(lpcStripReader) - 6] = '\0';
1056
1057			rv = RFRemoveReader(lpcStripReader, sReadersContexts[i]->dwPort);
1058
1059			if (rv != SCARD_S_SUCCESS)
1060				Log2(PCSC_LOG_ERROR, "RFRemoveReader error: 0x%08X", rv);
1061		}
1062	}
1063
1064	secdebug("pcscd", "RFCleanupReaders: exiting cleaning function");
1065	/*
1066	 * exit() will call at_exit()
1067	 */
1068
1069	if (shouldExit)
1070		exit(0);
1071}
1072
1073int RFStartSerialReaders(const char *readerconf)
1074{
1075	return DBUpdateReaders((char *)readerconf);
1076}
1077
1078void RFReCheckReaderConf(void)
1079{
1080}
1081
1082void RFSuspendAllReaders()
1083{
1084	int ix;
1085	secdebug("pcscd", "RFSuspendAllReaders");
1086	Log1(PCSC_LOG_DEBUG, "zzzzz zzzzz zzzzz zzzzz RFSuspendAllReaders zzzzz zzzzz zzzzz zzzzz ");
1087
1088	// @@@ We still need code to mark state first as "trying to sleep", in case
1089	// not all of it gets done before we sleep
1090	for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
1091	{
1092		if ((sReadersContexts[ix]!=NULL) && ((sReadersContexts[ix])->vHandle != 0))
1093		{
1094			EHDestroyEventHandler(sReadersContexts[ix]);
1095			IFDCloseIFD(sReadersContexts[ix]);
1096		}
1097	}
1098}
1099
1100void RFAwakeAllReaders(void)
1101{
1102	LONG rv = IFD_SUCCESS;
1103	int i;
1104
1105	secdebug("pcscd", "RFAwakeAllReaders");
1106	Log1(PCSC_LOG_DEBUG, "----- ----- ----- ----- RFAwakeAllReaders ----- ----- ----- -----  ");
1107	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1108	{
1109		if (sReadersContexts[i]==NULL)
1110			continue;
1111		/* If the library is loaded and the event handler is not running */
1112		if ( ((sReadersContexts[i])->vHandle   != 0) &&
1113		     ((sReadersContexts[i])->pthThread == 0) )
1114		{
1115			int jx;
1116			int alreadyInitializedFlag = 0;
1117
1118			// If a clone of this already did the initialization,
1119			// set flag so we don't do again
1120			for (jx=0; jx < i; jx++)
1121			{
1122				if (((sReadersContexts[jx])->vHandle == (sReadersContexts[i])->vHandle)&&
1123					((sReadersContexts[jx])->dwPort  == (sReadersContexts[i])->dwPort)&&
1124					((sReadersContexts[jx])->dwSlot  == (sReadersContexts[i])->dwSlot))
1125				{
1126					alreadyInitializedFlag = 1;
1127				}
1128			}
1129
1130			if (!alreadyInitializedFlag)
1131			{
1132				SYS_USleep(100000L);	// 0.1s (in microseconds)
1133				rv = IFDOpenIFD(sReadersContexts[i]);
1134			}
1135
1136			RFSetReaderEventState(sReadersContexts[i], SCARD_RESET);
1137			if (rv != IFD_SUCCESS)
1138			{
1139				Log3(PCSC_LOG_ERROR, "Open Port %X Failed (%s)",
1140					(sReadersContexts[i])->dwPort, (sReadersContexts[i])->lpcDevice);
1141				Log2(PCSC_LOG_ERROR, "  with error 0x%08X", rv);
1142				continue;
1143			}
1144
1145			EHSpawnEventHandler(sReadersContexts[i]);
1146		}
1147	}
1148}
1149
1150#pragma mark ---------- Context Share Lock Tracking ----------
1151
1152void ReaderContextLock(PREADER_CONTEXT rContext)
1153{
1154	if (rContext)
1155	{
1156		secdebug("pcscd", "===> ReaderContextLock [was: %02X]", rContext->dwLockId);
1157		rContext->dwLockId = 0xFFFF;
1158		lastLockID = -3;			// something different
1159	}
1160}
1161
1162void ReaderContextUnlock(PREADER_CONTEXT rContext)
1163{
1164	if (rContext)
1165	{
1166		secdebug("pcscd", "<=== ReaderContextUnlock [was: %02X]", rContext->dwLockId);
1167		rContext->dwLockId = 0;
1168		lastLockID = -2;			// something different
1169	}
1170}
1171
1172int ReaderContextIsLocked(PREADER_CONTEXT rContext)
1173{
1174	if (rContext)
1175	{
1176		if (rContext->dwLockId && (rContext->dwLockId != lastLockID))		// otherwise too many messages
1177		{
1178			lastLockID = rContext->dwLockId;
1179			secdebug("pcscd", ".... ReaderContextLock state: %02X", rContext->dwLockId);
1180		}
1181		return (rContext->dwLockId == 0xFFFF)?1:0;
1182	}
1183	else
1184		return 0;
1185}
1186
1187#pragma mark ---------- Reader Context Management ----------
1188
1189static int ReaderContextConstructor(PREADER_CONTEXT ctx, LPCSTR lpcReader,
1190	DWORD dwPort, LPCSTR lpcLibrary, LPCSTR lpcDevice)
1191{
1192	// We assume the struct was created with a calloc, so we don't call ReaderContextClear
1193	if (!ctx)
1194		return SCARD_E_NO_MEMORY;
1195
1196	strlcpy(ctx->lpcLibrary, lpcLibrary, sizeof(ctx->lpcLibrary));
1197	strlcpy(ctx->lpcDevice,  lpcDevice,  sizeof(ctx->lpcDevice));
1198	ctx->dwPort = dwPort;
1199
1200	/*
1201		Initialize pdwFeeds to 1, otherwise multiple cloned readers will cause
1202		pcscd to crash when RFUnloadReader unloads the driver library
1203		and there are still devices attached using it
1204	*/
1205	ctx->pdwFeeds = malloc(sizeof(DWORD));
1206	*ctx->pdwFeeds = 1;
1207
1208	ctx->mMutex = (PCSCLITE_MUTEX_T) malloc(sizeof(PCSCLITE_MUTEX));
1209	SYS_MutexInit(ctx->mMutex);
1210
1211	ctx->pdwMutex = malloc(sizeof(DWORD));
1212	*ctx->pdwMutex = 1;
1213
1214	return SCARD_S_SUCCESS;
1215}
1216
1217static int ReaderCheckForClone(PREADER_CONTEXT ctx, LPCSTR lpcReader,
1218	DWORD dwPort, LPCSTR lpcLibrary)
1219{
1220	// Check and set the readername to see if it must be enumerated
1221	// A parentNode of -2 or less indicates fatal error
1222
1223	LONG parentNode = RFSetReaderName(ctx, lpcReader, lpcLibrary, dwPort, 0);
1224	if (parentNode < -1)
1225		return SCARD_E_NO_MEMORY;
1226
1227	// If a clone to this reader exists take some values from that clone
1228	if ((parentNode >= 0) && (parentNode < PCSCLITE_MAX_READERS_CONTEXTS)
1229		&& sReadersContexts[parentNode])
1230	{
1231		SYS_MutexLock(sReadersContextsLock);
1232		ctx->pdwFeeds = (sReadersContexts[parentNode])->pdwFeeds;
1233		*ctx->pdwFeeds += 1;
1234		ctx->vHandle = (sReadersContexts[parentNode])->vHandle;
1235		ctx->mMutex = (sReadersContexts[parentNode])->mMutex;
1236		ctx->pdwMutex = (sReadersContexts[parentNode])->pdwMutex;
1237		SYS_MutexUnLock(sReadersContextsLock);
1238
1239		if (0 && ReaderDriverIsThreadSafe(sReadersContexts[parentNode], 0))
1240		{
1241			ctx->mMutex = 0;
1242			ctx->pdwMutex = NULL;
1243		}
1244		else
1245			*ctx->pdwMutex += 1;
1246	}
1247
1248	return SCARD_S_SUCCESS;
1249}
1250
1251static void ReaderContextDestructor(PREADER_CONTEXT ctx)
1252{
1253	ReaderContextFree(ctx);
1254}
1255
1256static void ReaderContextFree(PREADER_CONTEXT ctx)
1257{
1258	if (!ctx)
1259		return;
1260
1261	// Destroy and free the mutex
1262	if (ctx->pdwMutex)
1263	{
1264		if (*ctx->pdwMutex == 1)
1265		{
1266			SYS_MutexDestroy(ctx->mMutex);
1267			free(ctx->mMutex);
1268		}
1269		*ctx->pdwMutex -= 1;
1270	}
1271
1272	// Destroy and free the mutex counter
1273	if (ctx->pdwMutex && (*ctx->pdwMutex == 0))
1274	{
1275		free(ctx->pdwMutex);
1276		ctx->pdwMutex = NULL;
1277	}
1278
1279	if (ctx->pdwFeeds)
1280	{
1281		*ctx->pdwFeeds -= 1;
1282		if (*ctx->pdwFeeds == 0)
1283		{
1284			free(ctx->pdwFeeds);
1285			ctx->pdwFeeds = NULL;
1286		}
1287	}
1288
1289	// zero out everything else
1290	ReaderContextClear(ctx);
1291}
1292
1293static void ReaderContextClear(PREADER_CONTEXT ctx)
1294{
1295	// This assumes that ReaderContextFree has already been called if necessary
1296	if (ctx)
1297		memset(ctx, 0, sizeof(READER_CONTEXT));
1298}
1299
1300static int ReaderContextInsert(PREADER_CONTEXT ctx)
1301{
1302	// Find an empty slot to put the reader structure, and copy it in
1303	// If NULL is passed in, just return whether a spot is available or not
1304
1305	int ix, rv = SCARD_E_NO_MEMORY;
1306
1307	SYS_MutexLock(sReadersContextsLock);
1308	for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
1309	{
1310		if ((sReadersContexts[ix] == NULL) || (sReadersContexts[ix])->vHandle == 0)
1311		{
1312			if (ctx)
1313			{
1314				if (sReadersContexts[ix])
1315					free(sReadersContexts[ix]);
1316				sReadersContexts[ix] = ctx;
1317				(sReadersContexts[ix])->dwIdentity = (ix + 1) << (sizeof(DWORD) / 2) * 8;
1318				dwNumReadersContexts += 1;
1319			}
1320			rv = SCARD_S_SUCCESS;
1321			break;
1322		}
1323	}
1324	SYS_MutexUnLock(sReadersContextsLock);
1325	return rv;
1326}
1327
1328static int ReaderContextRemove(PREADER_CONTEXT ctx)
1329{
1330	int ix, rv = SCARD_E_UNKNOWN_READER;
1331	PREADER_CONTEXT ctxToRemove = NULL;
1332	DWORD dwPort = ctx->dwPort;
1333	LPSTR lpcReader = ctx->lpcReader;
1334	SYS_MutexLock(sReadersContextsLock);
1335	for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
1336	{
1337		if (!ReaderNameMatchForIndex(dwPort, lpcReader, ix))
1338			continue;
1339
1340		ctxToRemove = sReadersContexts[ix];
1341		sReadersContexts[ix] = NULL;
1342		dwNumReadersContexts -= 1;
1343		rv = SCARD_S_SUCCESS;
1344		break;
1345	}
1346	SYS_MutexUnLock(sReadersContextsLock);
1347	// We can do this cleanup outside the lock
1348	if (ctxToRemove)
1349	{
1350		ReaderContextDestructor(ctxToRemove);
1351		free(ctxToRemove);
1352	}
1353	return rv;
1354}
1355
1356static int ReaderContextCheckDuplicateReader(LPCSTR lpcReader, DWORD dwPort)
1357{
1358	// Readers with the same name and same port cannot be used
1359
1360	if (dwNumReadersContexts == 0)
1361		return SCARD_S_SUCCESS;
1362
1363	int ix, rv = SCARD_S_SUCCESS;
1364	SYS_MutexLock(sReadersContextsLock);
1365	for (ix = 0; ix < PCSCLITE_MAX_READERS_CONTEXTS; ix++)
1366	{
1367		if ((sReadersContexts[ix]==NULL) || ((sReadersContexts[ix])->vHandle == 0))
1368			continue;
1369
1370		if (ReaderNameMatchForIndex(dwPort, lpcReader, ix))
1371		{
1372			Log1(PCSC_LOG_ERROR, "Duplicate reader found.");
1373			rv = SCARD_E_DUPLICATE_READER;
1374			break;
1375		}
1376	}
1377	SYS_MutexUnLock(sReadersContextsLock);
1378	return rv;
1379}
1380
1381static int ReaderSlotCount(PREADER_CONTEXT ctx)
1382{
1383	// Call on the driver to see if there are multiple slots
1384	// If we encounter errors, pretend it is just a single slot reader
1385
1386	UCHAR ucGetData[1];
1387	DWORD dwGetSize = sizeof(ucGetData);
1388	int rv = IFDGetCapabilities(ctx, TAG_IFD_SLOTS_NUMBER, &dwGetSize, ucGetData);
1389
1390	//Reader does not have this defined, so assume a single slot
1391	if (rv != IFD_SUCCESS || dwGetSize != 1 || ucGetData[0] == 0)
1392		return 1;
1393
1394	// Reader has this defined and it only has one slot
1395	if (rv == IFD_SUCCESS && dwGetSize == 1 && ucGetData[0] == 1)
1396		return 1;
1397
1398	return (int)ucGetData[0];
1399}
1400
1401static BOOL ReaderDriverIsThreadSafe(PREADER_CONTEXT ctx, BOOL testSlot)
1402{
1403	// Call on the driver to see if it is thread safe
1404	UCHAR ucThread[1];
1405	DWORD dwGetSize = sizeof(ucThread);
1406	int rv = IFDGetCapabilities(ctx, testSlot?TAG_IFD_SLOT_THREAD_SAFE:TAG_IFD_THREAD_SAFE,
1407		&dwGetSize, ucThread);
1408	if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1)
1409	{
1410		Log1(PCSC_LOG_INFO, "Driver is thread safe");
1411		return 1;
1412	}
1413	else
1414	{
1415		Log1(PCSC_LOG_INFO, "Driver is not thread safe");
1416		return 0;
1417	}
1418}
1419
1420static BOOL ReaderNameMatchForIndex(DWORD dwPort, LPCSTR lpcReader, int index)
1421{
1422	// "index" is index in sReadersContexts
1423	char lpcStripReader[MAX_READERNAME];
1424	int tmplen;
1425
1426	if (sReadersContexts[index]==NULL)
1427		return 0;
1428
1429	strncpy(lpcStripReader, (sReadersContexts[index])->lpcReader, sizeof(lpcStripReader));
1430	tmplen = strlen(lpcStripReader);
1431	lpcStripReader[tmplen - 6] = 0;
1432
1433	return ((strcmp(lpcReader, lpcStripReader) == 0) && (dwPort == (sReadersContexts[index])->dwPort))?1:0;
1434}
1435
1436static void ReaderContextDuplicateSlot(PREADER_CONTEXT ctxBase, PREADER_CONTEXT ctxSlot, int slotNumber, BOOL baseIsThreadSafe)
1437{
1438	// Copy the previous reader name and set the slot number
1439	// The slot number for the base is 0
1440
1441	int ix;
1442	char *tmpReader = ctxSlot->lpcReader;
1443	strlcpy(tmpReader, ctxBase->lpcReader, sizeof(ctxSlot->lpcReader));
1444	sprintf(tmpReader + strlen(tmpReader) - 2, "%02X", slotNumber);
1445
1446	strlcpy(ctxSlot->lpcLibrary, ctxBase->lpcLibrary, sizeof(ctxSlot->lpcLibrary));
1447	strlcpy(ctxSlot->lpcDevice,  ctxBase->lpcDevice,  sizeof(ctxSlot->lpcDevice));
1448
1449	ctxSlot->dwVersion = ctxBase->dwVersion;
1450	ctxSlot->dwPort = ctxBase->dwPort;
1451	ctxSlot->vHandle = ctxBase->vHandle;
1452	ctxSlot->mMutex = ctxBase->mMutex;
1453	ctxSlot->pdwMutex = ctxBase->pdwMutex;
1454	ctxSlot->dwSlot = ctxBase->dwSlot + slotNumber;
1455
1456	ctxSlot->pdwFeeds = ctxBase->pdwFeeds;
1457
1458	*ctxSlot->pdwFeeds += 1;
1459
1460	ctxSlot->dwBlockStatus = 0;
1461	ctxSlot->dwContexts = 0;
1462	ctxSlot->dwLockId = 0;
1463	ctxSlot->readerState = NULL;
1464	ctxSlot->dwIdentity = (slotNumber + 1) << (sizeof(DWORD) / 2) * 8;
1465
1466	for (ix = 0; ix < PCSCLITE_MAX_READER_CONTEXT_CHANNELS; ix++)
1467		ctxSlot->psHandles[ix].hCard = 0;
1468
1469	if (!ctxSlot->pdwMutex)
1470		ctxSlot->pdwMutex = malloc(sizeof(DWORD));
1471	if (baseIsThreadSafe)
1472	{
1473		ctxSlot->mMutex = malloc(sizeof(PCSCLITE_MUTEX));
1474		SYS_MutexInit(ctxSlot->mMutex);
1475		*ctxSlot->pdwMutex = 1;
1476	}
1477	else
1478		*ctxSlot->pdwMutex += 1;
1479}
1480