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 *  ifdwrapper.c
26 *  SmartCardServices
27 */
28
29/*
30 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
31 *
32 * Copyright (C) 1999-2004
33 *  David Corcoran <corcoran@linuxnet.com>
34 *  Damien Sauveron <damien.sauveron@labri.fr>
35 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
36 *
37 * $Id: ifdwrapper.c 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
38 */
39
40/**
41 * @file
42 * @brief This wraps the dynamic ifdhandler functions.
43 */
44
45#include "config.h"
46#include "wintypes.h"
47#include "pcsclite.h"
48#include "ifdhandler.h"
49#include "debuglog.h"
50#include "readerfactory.h"
51#include "ifdwrapper.h"
52#include "atrhandler.h"
53#include "dyn_generic.h"
54#include "sys_generic.h"
55
56#include <security_utilities/debugging.h>
57
58#undef PCSCLITE_STATIC_DRIVER
59
60/**
61 * Set the protocol type selection (PTS).
62 * This function sets the appropriate protocol to be used on the card.
63 */
64LONG IFDSetPTS(PREADER_CONTEXT rContext, DWORD dwProtocol, UCHAR ucFlags,
65	UCHAR ucPTS1, UCHAR ucPTS2, UCHAR ucPTS3)
66{
67	RESPONSECODE rv = IFD_SUCCESS;
68	UCHAR ucValue[1];
69
70#ifndef PCSCLITE_STATIC_DRIVER
71	RESPONSECODE(*IFD_set_protocol_parameters) (DWORD, UCHAR, UCHAR,
72		UCHAR, UCHAR) = NULL;
73	RESPONSECODE(*IFDH_set_protocol_parameters) (DWORD, DWORD, UCHAR,
74		UCHAR, UCHAR, UCHAR) = NULL;
75
76	if (rContext->dwVersion == IFD_HVERSION_1_0)
77	{
78		IFD_set_protocol_parameters = (RESPONSECODE(*)(DWORD, UCHAR, UCHAR,
79			UCHAR, UCHAR)) rContext->psFunctions.psFunctions_v1.pvfSetProtocolParameters;
80
81		if (NULL == IFD_set_protocol_parameters)
82			return SCARD_E_UNSUPPORTED_FEATURE;
83	}
84	else
85	{
86		IFDH_set_protocol_parameters = (RESPONSECODE(*)(DWORD, DWORD, UCHAR,
87			UCHAR, UCHAR, UCHAR))
88			rContext->psFunctions.psFunctions_v2.pvfSetProtocolParameters;
89
90		if (NULL == IFDH_set_protocol_parameters)
91			return SCARD_E_UNSUPPORTED_FEATURE;
92	}
93#endif
94
95	/*
96	 * Locking is done in winscard.c SCardConnect() and SCardReconnect()
97	 *
98	 * This avoids renegotiating the protocol and confusing the card
99	 * Error returned by CCID driver is: CCID_Receive Procedure byte conflict
100	 */
101
102	ucValue[0] = rContext->dwSlot;
103
104#ifndef PCSCLITE_STATIC_DRIVER
105	if (rContext->dwVersion == IFD_HVERSION_1_0)
106	{
107	        ucValue[0] = rContext->dwSlot;
108	        (void)IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
109	        rv = (*IFD_set_protocol_parameters) (dwProtocol,
110			ucFlags, ucPTS1, ucPTS2, ucPTS3);
111	}
112	else
113	{
114		rv = (*IFDH_set_protocol_parameters) (rContext->dwSlot,
115						      dwProtocol,
116						      ucFlags, ucPTS1,
117						      ucPTS2, ucPTS3);
118	}
119#else
120	if (rContext->dwVersion == IFD_HVERSION_1_0)
121	{
122	        ucValue[0] = rContext->dwSlot;
123	        (void)IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
124		rv = IFD_Set_Protocol_Parameters(dwProtocol, ucFlags, ucPTS1,
125			ucPTS2, ucPTS3);
126	}
127	else
128	{
129		rv = IFDHSetProtocolParameters(rContext->dwSlot, dwProtocol,
130			ucFlags, ucPTS1, ucPTS2, ucPTS3);
131	}
132#endif
133
134	return rv;
135}
136
137/**
138 * Open a communication channel to the IFD.
139 */
140LONG IFDOpenIFD(PREADER_CONTEXT rContext)
141{
142	RESPONSECODE rv = 0;
143
144#ifndef PCSCLITE_STATIC_DRIVER
145	RESPONSECODE(*IO_create_channel) (DWORD) = NULL;
146	RESPONSECODE(*IFDH_create_channel) (DWORD, DWORD) = NULL;
147	RESPONSECODE(*IFDH_create_channel_by_name) (DWORD, LPSTR) = NULL;
148
149	if (rContext->dwVersion == IFD_HVERSION_1_0)
150		IO_create_channel =
151			rContext->psFunctions.psFunctions_v1.pvfCreateChannel;
152	else
153		if (rContext->dwVersion == IFD_HVERSION_2_0)
154			IFDH_create_channel =
155				rContext->psFunctions.psFunctions_v2.pvfCreateChannel;
156		else
157		{
158			IFDH_create_channel =
159				rContext->psFunctions.psFunctions_v3.pvfCreateChannel;
160			IFDH_create_channel_by_name =
161				rContext->psFunctions.psFunctions_v3.pvfCreateChannelByName;
162		}
163#endif
164
165	/* LOCK THIS CODE REGION */
166	(void)SYS_MutexLock(rContext->mMutex);
167
168#ifndef PCSCLITE_STATIC_DRIVER
169	if (rContext->dwVersion == IFD_HVERSION_1_0)
170	{
171		rv = (*IO_create_channel) (rContext->dwPort);
172	} else if (rContext->dwVersion == IFD_HVERSION_2_0)
173	{
174		rv = (*IFDH_create_channel) (rContext->dwSlot, rContext->dwPort);
175	} else
176	{
177		/* use device name only if defined */
178		if (rContext->lpcDevice[0] != '\0')
179			rv = (*IFDH_create_channel_by_name) (rContext->dwSlot, rContext->lpcDevice);
180		else
181			rv = (*IFDH_create_channel) (rContext->dwSlot, rContext->dwPort);
182	}
183#else
184	if (rContext->dwVersion == IFD_HVERSION_1_0)
185	{
186		rv = IO_Create_Channel(rContext->dwPort);
187	} else if (rContext->dwVersion == IFD_HVERSION_2_0)
188	{
189		rv = IFDHCreateChannel(rContext->dwSlot, rContext->dwPort);
190	} else
191	{
192		/* Use device name only if defined */
193		if (rContext->lpcDevice[0] != '\0')
194			rv = IFDHCreateChannelByName(rContext->dwSlot, rContext->lpcDevice);
195		else
196			rv = IFDHCreateChannel(rContext->dwSlot, rContext->dwPort);
197	}
198#endif
199
200	/* END OF LOCKED REGION */
201	(void)SYS_MutexUnLock(rContext->mMutex);
202
203	return rv;
204}
205
206/**
207 * Close a communication channel to the IFD.
208 */
209LONG IFDCloseIFD(PREADER_CONTEXT rContext)
210{
211	RESPONSECODE rv = IFD_SUCCESS;
212
213#ifndef PCSCLITE_STATIC_DRIVER
214	RESPONSECODE(*IO_close_channel) (void) = NULL;
215	RESPONSECODE(*IFDH_close_channel) (DWORD) = NULL;
216
217	if (rContext->dwVersion == IFD_HVERSION_1_0)
218		IO_close_channel = rContext->psFunctions.psFunctions_v1.pvfCloseChannel;
219	else
220		IFDH_close_channel = rContext->psFunctions.psFunctions_v2.pvfCloseChannel;
221#endif
222
223	/* LOCK THIS CODE REGION */
224	(void)SYS_MutexLock(rContext->mMutex);
225#ifndef PCSCLITE_STATIC_DRIVER
226	if (rContext->dwVersion == IFD_HVERSION_1_0)
227
228		rv = (*IO_close_channel) ();
229	else
230		rv = (*IFDH_close_channel) (rContext->dwSlot);
231#else
232	if (rContext->dwVersion == IFD_HVERSION_1_0)
233		rv = IO_Close_Channel();
234	else
235		rv = IFDHCloseChannel(rContext->dwSlot);
236#endif
237
238	/* END OF LOCKED REGION */
239	(void)SYS_MutexUnLock(rContext->mMutex);
240
241	return rv;
242}
243
244/**
245 * Set capabilities in the reader.
246 */
247LONG IFDSetCapabilities(PREADER_CONTEXT rContext, DWORD dwTag,
248			DWORD dwLength, PUCHAR pucValue)
249{
250	RESPONSECODE rv = IFD_SUCCESS;
251
252#ifndef PCSCLITE_STATIC_DRIVER
253	RESPONSECODE(*IFD_set_capabilities) (DWORD, PUCHAR) = NULL;
254	RESPONSECODE(*IFDH_set_capabilities) (DWORD, DWORD, DWORD, PUCHAR) = NULL;
255
256	if (rContext->dwVersion == IFD_HVERSION_1_0)
257		IFD_set_capabilities = rContext->psFunctions.psFunctions_v1.pvfSetCapabilities;
258	else
259		IFDH_set_capabilities = rContext->psFunctions.psFunctions_v2.pvfSetCapabilities;
260#endif
261
262	/*
263	 * Let the calling function lock this otherwise a deadlock will
264	 * result
265	 */
266
267#ifndef PCSCLITE_STATIC_DRIVER
268	if (rContext->dwVersion == IFD_HVERSION_1_0)
269		rv = (*IFD_set_capabilities) (dwTag, pucValue);
270	else
271		rv = (*IFDH_set_capabilities) (rContext->dwSlot, dwTag,
272			dwLength, pucValue);
273#else
274	if (rContext->dwVersion == IFD_HVERSION_1_0)
275		rv = IFD_Set_Capabilities(dwTag, pucValue);
276	else
277		rv = IFDHSetCapabilities(rContext->dwSlot, dwTag, dwLength,
278			pucValue);
279#endif
280
281	return rv;
282}
283
284/**
285 * Get's capabilities in the reader.
286 * Other functions int this file will call
287 * the driver directly to not cause a deadlock.
288 */
289LONG IFDGetCapabilities(PREADER_CONTEXT rContext, DWORD dwTag,
290	PDWORD pdwLength, PUCHAR pucValue)
291{
292	RESPONSECODE rv = IFD_SUCCESS;
293
294#ifndef PCSCLITE_STATIC_DRIVER
295	RESPONSECODE(*IFD_get_capabilities) (DWORD, /*@out@*/ PUCHAR) = NULL;
296	RESPONSECODE(*IFDH_get_capabilities) (DWORD, DWORD, PDWORD, /*@out@*/ PUCHAR) = NULL;
297
298	if (rContext->dwVersion == IFD_HVERSION_1_0)
299		IFD_get_capabilities =
300			rContext->psFunctions.psFunctions_v1.pvfGetCapabilities;
301	else
302		IFDH_get_capabilities =
303			rContext->psFunctions.psFunctions_v2.pvfGetCapabilities;
304#endif
305
306	/* LOCK THIS CODE REGION */
307	(void)SYS_MutexLock(rContext->mMutex);
308
309#ifndef PCSCLITE_STATIC_DRIVER
310	if (rContext->dwVersion == IFD_HVERSION_1_0)
311		rv = (*IFD_get_capabilities) (dwTag, pucValue);
312	else
313		rv = (*IFDH_get_capabilities) (rContext->dwSlot, dwTag,
314			pdwLength, pucValue);
315#else
316	if (rContext->dwVersion == IFD_HVERSION_1_0)
317		rv = IFD_Get_Capabilities(dwTag, pucValue);
318	else
319		rv = IFDHGetCapabilities(rContext->dwSlot, dwTag, pdwLength,
320			pucValue);
321#endif
322
323	/* END OF LOCKED REGION */
324	(void)SYS_MutexUnLock(rContext->mMutex);
325
326	return rv;
327}
328
329/**
330 * Power up/down or reset's an ICC located in the IFD.
331 */
332LONG IFDPowerICC(PREADER_CONTEXT rContext, DWORD dwAction,
333	const unsigned char *pucAtr, PDWORD pdwAtrLen)
334{
335	RESPONSECODE rv;
336	short ret;
337	SMARTCARD_EXTENSION sSmartCard;
338	DWORD dwStatus;
339	UCHAR ucValue[1];
340
341#ifndef PCSCLITE_STATIC_DRIVER
342	RESPONSECODE(*IFD_power_icc) (DWORD) = NULL;
343	RESPONSECODE(*IFDH_power_icc) (DWORD, DWORD, PUCHAR, PDWORD) = NULL;
344#endif
345
346	/*
347	 * Zero out everything
348	 */
349	rv = IFD_SUCCESS;
350	dwStatus = 0;
351	ucValue[0] = 0;
352
353	/*
354	 * Check that the card is inserted first
355	 */
356	(void)IFDStatusICC(rContext, &dwStatus, pucAtr, pdwAtrLen);
357
358	if (dwStatus & SCARD_ABSENT)
359		return SCARD_W_REMOVED_CARD;
360#ifndef PCSCLITE_STATIC_DRIVER
361	if (rContext->dwVersion == IFD_HVERSION_1_0)
362		IFD_power_icc = rContext->psFunctions.psFunctions_v1.pvfPowerICC;
363	else
364		IFDH_power_icc = rContext->psFunctions.psFunctions_v2.pvfPowerICC;
365#endif
366
367	/* LOCK THIS CODE REGION */
368	(void)SYS_MutexLock(rContext->mMutex);
369
370#ifndef PCSCLITE_STATIC_DRIVER
371	if (rContext->dwVersion == IFD_HVERSION_1_0)
372	{
373		ucValue[0] = rContext->dwSlot;
374		(void)IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
375		rv = (*IFD_power_icc) (dwAction);
376	}
377	else
378	{
379		rv = (*IFDH_power_icc) (rContext->dwSlot, dwAction,
380			(unsigned char *)pucAtr, pdwAtrLen);
381
382		ret = ATRDecodeAtr(&sSmartCard, pucAtr, *pdwAtrLen);
383	}
384#else
385	if (rContext->dwVersion == IFD_HVERSION_1_0)
386	{
387		ucValue[0] = rContext->dwSlot;
388		(void)IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
389		rv = IFD_Power_ICC(dwAction);
390	}
391	else
392		rv = IFDHPowerICC(rContext->dwSlot, dwAction, pucAtr, pdwAtrLen);
393#endif
394
395	/* END OF LOCKED REGION */
396	(void)SYS_MutexUnLock(rContext->mMutex);
397
398	/* use clean values in case of error */
399	if (rv != IFD_SUCCESS)
400	{
401		*pdwAtrLen = 0;
402//		pucAtr[0] = '\0';
403
404		if (rv == IFD_NO_SUCH_DEVICE)
405		{
406		//	(void)SendHotplugSignal();
407			return SCARD_E_READER_UNAVAILABLE;
408		}
409
410		return SCARD_E_NOT_TRANSACTED;
411	}
412
413	/*
414	 * Get the ATR and it's length
415	 */
416	if (rContext->dwVersion == IFD_HVERSION_1_0)
417		(void)IFDStatusICC(rContext, &dwStatus, pucAtr, pdwAtrLen);
418
419	return rv;
420}
421
422/**
423 * Provide statistical information about the IFD and ICC including insertions,
424 * atr, powering status/etc.
425 */
426LONG IFDStatusICC(PREADER_CONTEXT rContext, PDWORD pdwStatus,
427	const unsigned char *pucAtr, PDWORD pdwAtrLen)
428{
429	RESPONSECODE rv = IFD_SUCCESS;
430	DWORD dwTag = 0, dwCardStatus = 0;
431	SMARTCARD_EXTENSION sSmartCard;
432	UCHAR ucValue[1] = "\x00";
433
434#ifndef PCSCLITE_STATIC_DRIVER
435	RESPONSECODE(*IFD_is_icc_present) (void) = NULL;
436	RESPONSECODE(*IFDH_icc_presence) (DWORD) = NULL;
437	RESPONSECODE(*IFD_get_capabilities) (DWORD, /*@out@*/ PUCHAR) = NULL;
438
439	if (rContext->dwVersion == IFD_HVERSION_1_0)
440	{
441		IFD_is_icc_present =
442			rContext->psFunctions.psFunctions_v1.pvfICCPresence;
443		IFD_get_capabilities =
444			rContext->psFunctions.psFunctions_v1.pvfGetCapabilities;
445	}
446	else
447	{
448		IFDH_icc_presence = rContext->psFunctions.psFunctions_v2.pvfICCPresence;
449		// Defensive measure
450		if (!IFDH_icc_presence)
451			return SCARD_E_SYSTEM_CANCELLED;
452	}
453#endif
454
455	/* LOCK THIS CODE REGION */
456	(void)SYS_MutexLock(rContext->mMutex);
457
458#ifndef PCSCLITE_STATIC_DRIVER
459	if (rContext->dwVersion == IFD_HVERSION_1_0)
460	{
461		ucValue[0] = rContext->dwSlot;
462		(void)IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
463		rv = (*IFD_is_icc_present) ();
464	}
465	else
466		rv = (*IFDH_icc_presence) (rContext->dwSlot);
467#else
468	if (rContext->dwVersion == IFD_HVERSION_1_0)
469	{
470		ucValue[0] = rContext->dwSlot;
471		(void)IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
472		rv = IFD_Is_ICC_Present();
473	}
474	else
475		rv = IFDHICCPresence(rContext->dwSlot);
476#endif
477
478	/* END OF LOCKED REGION */
479	(void)SYS_MutexUnLock(rContext->mMutex);
480
481	if (rv == IFD_SUCCESS || rv == IFD_ICC_PRESENT)
482		dwCardStatus |= SCARD_PRESENT;
483	else
484		if (rv == IFD_ICC_NOT_PRESENT)
485			dwCardStatus |= SCARD_ABSENT;
486		else
487		{
488			Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
489			*pdwStatus = SCARD_UNKNOWN;
490
491			if (rv == IFD_NO_SUCH_DEVICE)
492			{
493			//	(void)SendHotplugSignal();
494				return SCARD_E_READER_UNAVAILABLE;
495			}
496
497			return SCARD_E_NOT_TRANSACTED;
498		}
499
500	/*
501	 * Now lets get the ATR and process it if IFD Handler version 1.0.
502	 * IFD Handler version 2.0 does this immediately after reset/power up
503	 * to conserve resources
504	 */
505
506	if (rContext->dwVersion == IFD_HVERSION_1_0)
507	{
508		if (rv == IFD_SUCCESS || rv == IFD_ICC_PRESENT)
509		{
510			short ret;
511
512			dwTag = TAG_IFD_ATR;
513
514			/* LOCK THIS CODE REGION */
515			(void)SYS_MutexLock(rContext->mMutex);
516
517			ucValue[0] = rContext->dwSlot;
518			(void)IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
519
520#ifndef PCSCLITE_STATIC_DRIVER
521			rv = (*IFD_get_capabilities) (dwTag, (unsigned char *)pucAtr);
522#else
523			rv = IFD_Get_Capabilities(dwTag, pucAtr);
524#endif
525
526			/* END OF LOCKED REGION */
527			(void)SYS_MutexUnLock(rContext->mMutex);
528
529			/*
530			 * FIX :: This is a temporary way to return the correct size
531			 * of the ATR since most of the drivers return MAX_ATR_SIZE
532			 */
533
534			ret = ATRDecodeAtr(&sSmartCard, pucAtr, MAX_ATR_SIZE);
535
536			/*
537			 * Might be a memory card without an ATR
538			 */
539			if (ret == 0)
540				*pdwAtrLen = 0;
541			else
542				*pdwAtrLen = sSmartCard.ATR.Length;
543		}
544		else
545		{
546			/*
547			 * No card is inserted - Atr length is 0
548			 */
549			*pdwAtrLen = 0;
550		}
551		/*
552		 * End of FIX
553		 */
554	}
555
556	*pdwStatus = dwCardStatus;
557
558	return SCARD_S_SUCCESS;
559}
560
561/*
562 * Function: IFDControl Purpose : This function provides a means for
563 * toggling a specific action on the reader such as swallow, eject,
564 * biometric.
565 */
566
567/*
568 * Valid only for IFDHandler version 2.0
569 */
570
571LONG IFDControl_v2(PREADER_CONTEXT rContext, PUCHAR TxBuffer,
572	DWORD TxLength, PUCHAR RxBuffer, PDWORD RxLength)
573{
574	RESPONSECODE rv = IFD_SUCCESS;
575
576#ifndef PCSCLITE_STATIC_DRIVER
577	RESPONSECODE(*IFDH_control_v2) (DWORD, PUCHAR, DWORD, /*@out@*/ PUCHAR,
578		PDWORD);
579#endif
580
581	if (rContext->dwVersion != IFD_HVERSION_2_0)
582		return SCARD_E_UNSUPPORTED_FEATURE;
583
584#ifndef PCSCLITE_STATIC_DRIVER
585	IFDH_control_v2 = rContext->psFunctions.psFunctions_v2.pvfControl;
586#endif
587
588	/* LOCK THIS CODE REGION */
589	(void)SYS_MutexLock(rContext->mMutex);
590
591#ifndef PCSCLITE_STATIC_DRIVER
592	rv = (*IFDH_control_v2) (rContext->dwSlot, TxBuffer, TxLength,
593		RxBuffer, RxLength);
594#else
595	rv = IFDHControl_v2(rContext->dwSlot, TxBuffer, TxLength,
596		RxBuffer, RxLength);
597#endif
598
599	/* END OF LOCKED REGION */
600	(void)SYS_MutexUnLock(rContext->mMutex);
601
602	if (rv == IFD_SUCCESS)
603		return SCARD_S_SUCCESS;
604	else
605	{
606		Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
607		LogXxd(PCSC_LOG_DEBUG, "TxBuffer ", TxBuffer, TxLength);
608		LogXxd(PCSC_LOG_DEBUG, "RxBuffer ", RxBuffer, *RxLength);
609		return SCARD_E_NOT_TRANSACTED;
610	}
611}
612
613/**
614 * Provide a means for toggling a specific action on the reader such as
615 * swallow, eject, biometric.
616 */
617
618/*
619 * Valid only for IFDHandler version 3.0 and up
620 */
621
622LONG IFDControl(PREADER_CONTEXT rContext, DWORD ControlCode,
623	LPCVOID TxBuffer, DWORD TxLength, LPVOID RxBuffer, DWORD RxLength,
624	LPDWORD BytesReturned)
625{
626	RESPONSECODE rv = IFD_SUCCESS;
627
628#ifndef PCSCLITE_STATIC_DRIVER
629	RESPONSECODE(*IFDH_control) (DWORD, DWORD, LPCVOID, DWORD, LPVOID, DWORD, LPDWORD);
630#endif
631
632	if (rContext->dwVersion < IFD_HVERSION_3_0)
633		return SCARD_E_UNSUPPORTED_FEATURE;
634
635#ifndef PCSCLITE_STATIC_DRIVER
636	IFDH_control = rContext->psFunctions.psFunctions_v3.pvfControl;
637#endif
638
639	/* LOCK THIS CODE REGION */
640	(void)SYS_MutexLock(rContext->mMutex);
641
642#ifndef PCSCLITE_STATIC_DRIVER
643	rv = (*IFDH_control) (rContext->dwSlot, ControlCode, TxBuffer,
644		TxLength, RxBuffer, RxLength, BytesReturned);
645#else
646	rv = IFDHControl(rContext->dwSlot, ControlCode, TxBuffer,
647		TxLength, RxBuffer, RxLength, BytesReturned);
648#endif
649
650	/* END OF LOCKED REGION */
651	(void)SYS_MutexUnLock(rContext->mMutex);
652
653	if (rv == IFD_SUCCESS)
654		return SCARD_S_SUCCESS;
655	else
656	{
657		Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
658		Log3(PCSC_LOG_DEBUG, "ControlCode: 0x%.8LX BytesReturned: %ld",
659			ControlCode, *BytesReturned);
660		LogXxd(PCSC_LOG_DEBUG, "TxBuffer ", TxBuffer, TxLength);
661		LogXxd(PCSC_LOG_DEBUG, "RxBuffer ", RxBuffer, *BytesReturned);
662
663		if (rv == IFD_NO_SUCH_DEVICE)
664		{
665//			(void)SendHotplugSignal();
666			return SCARD_E_READER_UNAVAILABLE;
667		}
668
669		return SCARD_E_NOT_TRANSACTED;
670	}
671}
672
673/**
674 * Transmit an APDU to the ICC.
675 */
676LONG IFDTransmit(PREADER_CONTEXT rContext, SCARD_IO_HEADER pioTxPci,
677	PUCHAR pucTxBuffer, DWORD dwTxLength, PUCHAR pucRxBuffer,
678	PDWORD pdwRxLength, PSCARD_IO_HEADER pioRxPci)
679{
680	RESPONSECODE rv = IFD_SUCCESS;
681	UCHAR ucValue[1] = "\x00";
682
683#ifndef PCSCLITE_STATIC_DRIVER
684	RESPONSECODE(*IFD_transmit_to_icc) (SCARD_IO_HEADER, PUCHAR, DWORD,
685		/*@out@*/ PUCHAR, PDWORD, PSCARD_IO_HEADER) = NULL;
686	RESPONSECODE(*IFDH_transmit_to_icc) (DWORD, SCARD_IO_HEADER, PUCHAR,
687		DWORD, /*@out@*/ PUCHAR, PDWORD, PSCARD_IO_HEADER) = NULL;
688#endif
689
690	/* log the APDU */
691	DebugLogCategory(DEBUG_CATEGORY_APDU, pucTxBuffer, dwTxLength);
692
693#ifndef PCSCLITE_STATIC_DRIVER
694	if (rContext->dwVersion == IFD_HVERSION_1_0)
695		IFD_transmit_to_icc =
696			rContext->psFunctions.psFunctions_v1.pvfTransmitToICC;
697	else
698		IFDH_transmit_to_icc =
699			rContext->psFunctions.psFunctions_v2.pvfTransmitToICC;
700#endif
701
702	/* LOCK THIS CODE REGION */
703	(void)SYS_MutexLock(rContext->mMutex);
704
705#ifndef PCSCLITE_STATIC_DRIVER
706	if (rContext->dwVersion == IFD_HVERSION_1_0)
707	{
708		ucValue[0] = rContext->dwSlot;
709		(void)IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
710		rv = (*IFD_transmit_to_icc) (pioTxPci, (LPBYTE) pucTxBuffer,
711			dwTxLength, pucRxBuffer, pdwRxLength, pioRxPci);
712	}
713	else
714		rv = (*IFDH_transmit_to_icc) (rContext->dwSlot, pioTxPci,
715			(LPBYTE) pucTxBuffer, dwTxLength,
716			pucRxBuffer, pdwRxLength, pioRxPci);
717#else
718	if (rContext->dwVersion == IFD_HVERSION_1_0)
719	{
720		ucValue[0] = rContext->dwSlot;
721		(void)IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
722		rv = IFD_Transmit_to_ICC(pioTxPci, (LPBYTE) pucTxBuffer,
723			dwTxLength, pucRxBuffer, pdwRxLength, pioRxPci);
724	}
725	else
726		rv = IFDHTransmitToICC(rContext->dwSlot, pioTxPci,
727			(LPBYTE) pucTxBuffer, dwTxLength,
728			pucRxBuffer, pdwRxLength, pioRxPci);
729#endif
730
731	/* END OF LOCKED REGION */
732	(void)SYS_MutexUnLock(rContext->mMutex);
733
734	/* log the returned status word */
735	DebugLogCategory(DEBUG_CATEGORY_SW, pucRxBuffer, *pdwRxLength);
736
737	if (rv == IFD_SUCCESS)
738		return SCARD_S_SUCCESS;
739	else
740	{
741		Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
742
743		if (rv == IFD_NO_SUCH_DEVICE)
744		{
745	//		(void)SendHotplugSignal();
746			return SCARD_E_READER_UNAVAILABLE;
747		}
748
749		return SCARD_E_NOT_TRANSACTED;
750	}
751}
752
753