LONG EHDestroyEventHandler(PREADER_CONTEXT rContext)
{
	if (NULL == rContext->readerState)
	{
		Log1(PCSC_LOG_ERROR, "Thread never started (reader init failed?)");
		return SCARD_S_SUCCESS;
	}

	PCSCD::SharedReaderState *rs = PCSCD::SharedReaderState::overlay(rContext->readerState);
	if ((rContext->pthThread == 0) || !rs || (rs->readerNameLength() == 0))
	{
		Log1(PCSC_LOG_INFO, "Thread already stomped.");
		return SCARD_S_SUCCESS;
	}

	secdebug("pcscd", "EHDestroyEventHandler: pthThread: %p, reader name len: %ld",
		rContext->pthThread, rs->readerNameLength());

	/*
	 * Zero out the public status struct to allow it to be recycled and
	 * used again
	 */

	rs->xreaderNameClear();
	rs->xcardAtrClear();
	rs->xreaderID(0);
	rs->xreaderState(0);
	rs->xlockState(0);
	rs->sharing(0);
	rs->xcardAtrLength(0);
	rs->xcardProtocol(SCARD_PROTOCOL_UNSET);		// we only set this one to write to memory cache

	/*
	 * Set the thread to 0 to exit thread
	 */
	ReaderContextLock(rContext);

	Log1(PCSC_LOG_INFO, "Stomping thread.");

	int ix;
	for (ix = 0; (ix < 100) && ReaderContextIsLocked(rContext); ++ix)
	{
		/*
		 * Wait 0.05 seconds for the child to respond
		 */
		SYS_USleep(50000);
	}

	secdebug("pcscd", "EHDestroyEventHandler: post-stop dwLockId: %d", rContext->dwLockId);


	/* Zero the thread */
	rContext->pthThread = 0;

	Log1(PCSC_LOG_INFO, "Thread stomped.");

	return SCARD_S_SUCCESS;
}
Пример #2
0
/**
 * Close a communication channel to the IFD.
 */
LONG IFDCloseIFD(PREADER_CONTEXT rContext)
{
	RESPONSECODE rv = IFD_SUCCESS;
	int repeat;

#ifndef PCSCLITE_STATIC_DRIVER
	RESPONSECODE(*IO_close_channel) (void) = NULL;
	RESPONSECODE(*IFDH_close_channel) (DWORD) = NULL;

	if (rContext->dwVersion == IFD_HVERSION_1_0)
		IO_close_channel = rContext->psFunctions.psFunctions_v1.pvfCloseChannel;
	else
		IFDH_close_channel = rContext->psFunctions.psFunctions_v2.pvfCloseChannel;
#endif

	/* TRY TO LOCK THIS CODE REGION */
	repeat = 5;
again:
	rv = SYS_MutexTryLock(rContext->mMutex);
	if (EBUSY == rv)
	{
		Log1(PCSC_LOG_ERROR, "Locking failed");
		repeat--;
		if (repeat)
		{
			(void)SYS_USleep(100*1000);	/* 100 ms */
			goto again;
		}
	}

#ifndef PCSCLITE_STATIC_DRIVER
	if (rContext->dwVersion == IFD_HVERSION_1_0)

		rv = (*IO_close_channel) ();
	else
		rv = (*IFDH_close_channel) (rContext->dwSlot);
#else
	if (rContext->dwVersion == IFD_HVERSION_1_0)
		rv = IO_Close_Channel();
	else
		rv = IFDHCloseChannel(rContext->dwSlot);
#endif

	/* END OF LOCKED REGION */
	(void)SYS_MutexUnLock(rContext->mMutex);

	return rv;
}
Пример #3
0
/**
 * Close a communication channel to the IFD.
 */
LONG IFDCloseIFD(READER_CONTEXT * rContext)
{
	RESPONSECODE rv;
	int repeat;

#ifndef PCSCLITE_STATIC_DRIVER
	RESPONSECODE(*IFDH_close_channel) (DWORD) = NULL;

	IFDH_close_channel = rContext->psFunctions.psFunctions_v2.pvfCloseChannel;
#endif

	/* TRY TO LOCK THIS CODE REGION */
	repeat = 5;
again:
	rv = pthread_mutex_trylock(rContext->mMutex);
	if (EBUSY == rv)
	{
		Log1(PCSC_LOG_ERROR, "Locking failed");
		repeat--;
		if (repeat)
		{
			(void)SYS_USleep(100*1000);	/* 100 ms */
			goto again;
		}
	}

#ifndef PCSCLITE_STATIC_DRIVER
	rv = (*IFDH_close_channel) (rContext->slot);
#else
	rv = IFDHCloseChannel(rContext->slot);
#endif

	/* END OF LOCKED REGION */
	(void)pthread_mutex_unlock(rContext->mMutex);

	return rv;
}
Пример #4
0
LONG SCardConnect(/*@unused@*/ SCARDCONTEXT hContext, LPCSTR szReader,
	DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
	LPDWORD pdwActiveProtocol)
{
	LONG rv;
	PREADER_CONTEXT rContext = NULL;
	DWORD dwStatus;

	(void)hContext;
	PROFILE_START

	/*
	 * Check for NULL parameters
	 */
	if (szReader == NULL || phCard == NULL || pdwActiveProtocol == NULL)
		return SCARD_E_INVALID_PARAMETER;
	else
		*phCard = 0;

	if ((dwShareMode != SCARD_SHARE_DIRECT) &&
			!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
			!(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
			!(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
			!(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
		return SCARD_E_PROTO_MISMATCH;

	if (dwShareMode != SCARD_SHARE_EXCLUSIVE &&
			dwShareMode != SCARD_SHARE_SHARED &&
			dwShareMode != SCARD_SHARE_DIRECT)
		return SCARD_E_INVALID_VALUE;

	Log3(PCSC_LOG_DEBUG, "Attempting Connect to %s using protocol: %d",
		szReader, dwPreferredProtocols);

	rv = RFReaderInfo((LPSTR) szReader, &rContext);

	if (rv != SCARD_S_SUCCESS)
	{
		Log2(PCSC_LOG_ERROR, "Reader %s Not Found", szReader);
		return rv;
	}

	/*
	 * Make sure the reader is working properly
	 */
	rv = RFCheckReaderStatus(rContext);
	if (rv != SCARD_S_SUCCESS)
		return rv;

	/*******************************************
	 *
	 * This section checks for simple errors
	 *
	 *******************************************/

	/*
	 * Connect if not exclusive mode
	 */
	if (rContext->dwContexts == SCARD_EXCLUSIVE_CONTEXT)
	{
		Log1(PCSC_LOG_ERROR, "Error Reader Exclusive");
		return SCARD_E_SHARING_VIOLATION;
	}

	/*
	 * wait until a possible transaction is finished
	 */
	if (rContext->dwLockId != 0)
	{
		Log1(PCSC_LOG_INFO, "Waiting for release of lock");
		while (rContext->dwLockId != 0)
			(void)SYS_USleep(PCSCLITE_LOCK_POLL_RATE);
		Log1(PCSC_LOG_INFO, "Lock released");
	}

	/* the reader has been removed while we were waiting */
	if (NULL == rContext->readerState)
		return SCARD_E_NO_SMARTCARD;

	/*******************************************
	 *
	 * This section tries to determine the
	 * presence of a card or not
	 *
	 *******************************************/
	dwStatus = rContext->readerState->readerState;

	if (dwShareMode != SCARD_SHARE_DIRECT)
	{
		if (!(dwStatus & SCARD_PRESENT))
		{
			Log1(PCSC_LOG_ERROR, "Card Not Inserted");
			return SCARD_E_NO_SMARTCARD;
		}

		if (dwStatus & SCARD_SWALLOWED)
		{
			Log1(PCSC_LOG_ERROR, "Card Not Powered");
			return SCARD_W_UNPOWERED_CARD;
		}
	}


	/*******************************************
	 *
	 * This section tries to decode the ATR
	 * and set up which protocol to use
	 *
	 *******************************************/
	if (dwPreferredProtocols & SCARD_PROTOCOL_RAW)
		rContext->readerState->cardProtocol = SCARD_PROTOCOL_RAW;
	else
	{
		if (dwShareMode != SCARD_SHARE_DIRECT)
		{
			/* lock here instead in IFDSetPTS() to lock up to
			 * setting rContext->readerState->cardProtocol */
			(void)SYS_MutexLock(rContext->mMutex);

			/* the protocol is not yet set (no PPS yet) */
			if (SCARD_PROTOCOL_UNDEFINED == rContext->readerState->cardProtocol)
			{
				UCHAR ucAvailable, ucDefault;
				int ret;

				ucDefault = PHGetDefaultProtocol(rContext->readerState->cardAtr,
					rContext->readerState->cardAtrLength);
				ucAvailable =
					PHGetAvailableProtocols(rContext->readerState->cardAtr,
							rContext->readerState->cardAtrLength);

				/*
				 * If it is set to ANY let it do any of the protocols
				 */
				if (dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD)
					dwPreferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;

				ret = PHSetProtocol(rContext, dwPreferredProtocols,
					ucAvailable, ucDefault);

				/* keep cardProtocol = SCARD_PROTOCOL_UNDEFINED in case of error  */
				if (SET_PROTOCOL_PPS_FAILED == ret)
				{
					(void)SYS_MutexUnLock(rContext->mMutex);
					return SCARD_W_UNRESPONSIVE_CARD;
				}

				if (SET_PROTOCOL_WRONG_ARGUMENT == ret)
				{
					(void)SYS_MutexUnLock(rContext->mMutex);
					return SCARD_E_PROTO_MISMATCH;
				}

				/* use negotiated protocol */
				rContext->readerState->cardProtocol = ret;

				(void)SYS_MutexUnLock(rContext->mMutex);
			}
			else
			{
				(void)SYS_MutexUnLock(rContext->mMutex);

				if (! (dwPreferredProtocols & rContext->readerState->cardProtocol))
					return SCARD_E_PROTO_MISMATCH;
			}
		}
		else
			rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
	}

	*pdwActiveProtocol = rContext->readerState->cardProtocol;

	if (dwShareMode != SCARD_SHARE_DIRECT)
	{
		if ((*pdwActiveProtocol != SCARD_PROTOCOL_T0)
			&& (*pdwActiveProtocol != SCARD_PROTOCOL_T1))
			Log2(PCSC_LOG_ERROR, "Active Protocol: unknown %d",
				*pdwActiveProtocol);
		else
			Log2(PCSC_LOG_DEBUG, "Active Protocol: T=%d",
				(*pdwActiveProtocol == SCARD_PROTOCOL_T0) ? 0 : 1);
	}
	else
		Log1(PCSC_LOG_DEBUG, "Direct access: no protocol selected");

	/*
	 * Prepare the SCARDHANDLE identity
	 */
	*phCard = RFCreateReaderHandle(rContext);

	Log2(PCSC_LOG_DEBUG, "hCard Identity: %x", *phCard);

	/*******************************************
	 *
	 * This section tries to set up the
	 * exclusivity modes. -1 is exclusive
	 *
	 *******************************************/

	if (dwShareMode == SCARD_SHARE_EXCLUSIVE)
	{
		if (rContext->dwContexts == SCARD_NO_CONTEXT)
		{
			rContext->dwContexts = SCARD_EXCLUSIVE_CONTEXT;
			(void)RFLockSharing(*phCard);
		}
		else
		{
			(void)RFDestroyReaderHandle(*phCard);
			*phCard = 0;
			return SCARD_E_SHARING_VIOLATION;
		}
	}
	else
	{
		/*
		 * Add a connection to the context stack
		 */
		rContext->dwContexts += 1;
	}

	/*
	 * Add this handle to the handle list
	 */
	rv = RFAddReaderHandle(rContext, *phCard);

	if (rv != SCARD_S_SUCCESS)
	{
		/*
		 * Clean up - there is no more room
		 */
		(void)RFDestroyReaderHandle(*phCard);
		if (rContext->dwContexts == SCARD_EXCLUSIVE_CONTEXT)
			rContext->dwContexts = SCARD_NO_CONTEXT;
		else
			if (rContext->dwContexts > SCARD_NO_CONTEXT)
				rContext->dwContexts -= 1;

		*phCard = 0;

		PROFILE_END

		return SCARD_F_INTERNAL_ERROR;
	}
Пример #5
0
static void EHStatusHandlerThread(READER_CONTEXT * rContext)
{
	LONG rv;
	const char *readerName;
	DWORD dwStatus;
	uint32_t readerState;
	int32_t readerSharing;
	DWORD dwCurrentState;
	DWORD dwAtrLen;

	/*
	 * Zero out everything
	 */
	dwStatus = 0;

	readerName = rContext->readerState->readerName;

	rv = IFDStatusICC(rContext, &dwStatus);

	if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
	{
#ifdef DISABLE_AUTO_POWER_ON
		rContext->readerState->cardAtrLength = 0;
		rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
		readerState = SCARD_PRESENT;
		Log1(PCSC_LOG_INFO, "Skip card power on");
#else
		dwAtrLen = sizeof(rContext->readerState->cardAtr);
		rv = IFDPowerICC(rContext, IFD_POWER_UP,
			rContext->readerState->cardAtr, &dwAtrLen);
		rContext->readerState->cardAtrLength = dwAtrLen;

		/* the protocol is unset after a power on */
		rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;

		if (rv == IFD_SUCCESS)
		{
			readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
			rContext->powerState = POWER_STATE_POWERED;
			Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");

			if (rContext->readerState->cardAtrLength > 0)
			{
				LogXxd(PCSC_LOG_INFO, "Card ATR: ",
					rContext->readerState->cardAtr,
					rContext->readerState->cardAtrLength);
			}
			else
				Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
		}
		else
		{
			readerState = SCARD_PRESENT | SCARD_SWALLOWED;
			rContext->powerState = POWER_STATE_UNPOWERED;
			Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
			Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv);
		}
#endif

		dwCurrentState = SCARD_PRESENT;
	}
	else
	{
		readerState = SCARD_ABSENT;
		rContext->readerState->cardAtrLength = 0;
		rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;

		dwCurrentState = SCARD_ABSENT;
	}

	/*
	 * Set all the public attributes to this reader
	 */
	rContext->readerState->readerState = readerState;
	rContext->readerState->readerSharing = readerSharing = rContext->contexts;

	(void)EHSignalEventToClients();

	while (1)
	{
		dwStatus = 0;

		rv = IFDStatusICC(rContext, &dwStatus);

		if (rv != SCARD_S_SUCCESS)
		{
			Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);

			/*
			 * Set error status on this reader while errors occur
			 */
			rContext->readerState->readerState = SCARD_UNKNOWN;
			rContext->readerState->cardAtrLength = 0;
			rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;

			dwCurrentState = SCARD_UNKNOWN;

			(void)EHSignalEventToClients();
		}

		if (dwStatus & SCARD_ABSENT)
		{
			if (dwCurrentState == SCARD_PRESENT ||
				dwCurrentState == SCARD_UNKNOWN)
			{
				/*
				 * Change the status structure
				 */
				Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
				/*
				 * Notify the card has been removed
				 */
				(void)RFSetReaderEventState(rContext, SCARD_REMOVED);

				rContext->readerState->cardAtrLength = 0;
				rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
				rContext->readerState->readerState = SCARD_ABSENT;
				dwCurrentState = SCARD_ABSENT;

				rContext->readerState->eventCounter++;

				(void)EHSignalEventToClients();
			}

		}
		else if (dwStatus & SCARD_PRESENT)
		{
			if (dwCurrentState == SCARD_ABSENT ||
				dwCurrentState == SCARD_UNKNOWN)
			{
#ifdef DISABLE_AUTO_POWER_ON
				rContext->readerState->cardAtrLength = 0;
				rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
				rContext->readerState->readerState = SCARD_PRESENT;
				rContext->powerState = POWER_STATE_UNPOWERED;
				Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
				readerState = SCARD_PRESENT;
				rv = IFD_SUCCESS;
				Log1(PCSC_LOG_INFO, "Skip card power on");
#else
				/*
				 * Power and reset the card
				 */
				dwAtrLen = sizeof(rContext->readerState->cardAtr);
				rv = IFDPowerICC(rContext, IFD_POWER_UP,
					rContext->readerState->cardAtr, &dwAtrLen);
				rContext->readerState->cardAtrLength = dwAtrLen;

				/* the protocol is unset after a power on */
				rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;

				if (rv == IFD_SUCCESS)
				{
					rContext->readerState->readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
					rContext->powerState = POWER_STATE_POWERED;
					Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
				}
				else
				{
					rContext->readerState->readerState = SCARD_PRESENT | SCARD_SWALLOWED;
					rContext->powerState = POWER_STATE_UNPOWERED;
					Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
					rContext->readerState->cardAtrLength = 0;
				}
#endif

				dwCurrentState = SCARD_PRESENT;

				rContext->readerState->eventCounter++;

				Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);

				(void)EHSignalEventToClients();

				if (rv == IFD_SUCCESS)
				{
					if (rContext->readerState->cardAtrLength > 0)
					{
						LogXxd(PCSC_LOG_INFO, "Card ATR: ",
							rContext->readerState->cardAtr,
							rContext->readerState->cardAtrLength);
					}
					else
						Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
				}
				else
					Log1(PCSC_LOG_ERROR,"Error powering up card.");
			}
		}

		/*
		 * Sharing may change w/o an event pass it on
		 */
		if (readerSharing != rContext->contexts)
		{
			readerSharing = rContext->contexts;
			rContext->readerState->readerSharing = readerSharing;
			(void)EHSignalEventToClients();
		}

		if (rContext->pthCardEvent)
		{
			int ret;
			int timeout;

#ifndef DISABLE_ON_DEMAND_POWER_ON
			if (POWER_STATE_POWERED == rContext->powerState)
				/* The card is powered but not yet used */
				timeout = PCSCLITE_POWER_OFF_GRACE_PERIOD;
			else
				/* The card is already in use or not used at all */
#endif
				timeout = PCSCLITE_STATUS_EVENT_TIMEOUT;

			ret = rContext->pthCardEvent(rContext->slot, timeout);
			if (IFD_SUCCESS != ret)
				(void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
		}
		else
			(void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);

#ifndef DISABLE_ON_DEMAND_POWER_ON
		/* the card is powered but not used */
		(void)pthread_mutex_lock(&rContext->powerState_lock);
		if (POWER_STATE_POWERED == rContext->powerState)
		{
			/* power down */
			IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
			rContext->powerState = POWER_STATE_UNPOWERED;
			Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");

			/* the protocol is unset after a power down */
			rContext->readerState->cardProtocol = SCARD_PROTOCOL_UNDEFINED;
		}

		/* the card was in use */
		if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
		{
			/* the next state should be UNPOWERED unless the
			 * card is used again */
			rContext->powerState = POWER_STATE_POWERED;
			Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
		}
		(void)pthread_mutex_unlock(&rContext->powerState_lock);
#endif

		if (rContext->hLockId == 0xFFFF)
		{
			/*
			 * Exit and notify the caller
			 */
			(void)EHSignalEventToClients();
			Log1(PCSC_LOG_INFO, "Die");
			rContext->hLockId = 0;
			(void)pthread_exit(NULL);
		}
	}
}
void EHStatusHandlerThread(PREADER_CONTEXT rContext)
{
	LONG rv;
	LPCSTR lpcReader;
	DWORD dwStatus, dwReaderSharing;
	DWORD dwCurrentState;
	int pageSize = SYS_GetPageSize();

	/*
	 * Zero out everything
	 */
	dwStatus = 0;
	dwReaderSharing = 0;
	dwCurrentState = 0;

	secdebug("pcscd", "EHStatusHandlerThread: rContext: 0x%p", rContext);
	lpcReader = rContext->lpcReader;

	PCSCD::SharedReaderState *rs = PCSCD::SharedReaderState::overlay(rContext->readerState);

	DWORD tmpCardAtrLength = MAX_ATR_SIZE;
	rv = IFDStatusICC(rContext, &dwStatus, rs->xcardAtr(), &tmpCardAtrLength);
	secdebug("pcscd", "EHStatusHandlerThread: initial call to IFDStatusICC: %d [%04X]", rv, rv);

	if (dwStatus & SCARD_PRESENT)
	{
		tmpCardAtrLength = MAX_ATR_SIZE;
		rv = IFDPowerICC(rContext, IFD_POWER_UP, rs->xcardAtr(), &tmpCardAtrLength);

		/* the protocol is unset after a power on */
		rs->xcardProtocol(SCARD_PROTOCOL_UNSET);

		secdebug("pcscd", "EHStatusHandlerThread: initial call to IFDPowerICC: %d [%04X]", rv, rv);

		if (rv == IFD_SUCCESS)
		{
			rs->xcardAtrLength(tmpCardAtrLength);

			dwStatus |= SCARD_PRESENT;
			dwStatus &= ~SCARD_ABSENT;
			dwStatus |= SCARD_POWERED;
			dwStatus |= SCARD_NEGOTIABLE;
			dwStatus &= ~SCARD_SPECIFIC;
			dwStatus &= ~SCARD_SWALLOWED;
			dwStatus &= ~SCARD_UNKNOWN;

			if (rs->xcardAtrLength() > 0)
			{
				LogXxd(PCSC_LOG_INFO, "Card ATR: ",
					rs->xcardAtr(),
					rs->xcardAtrLength());
			}
			else
				Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
		}
		else
		{
			dwStatus |= SCARD_PRESENT;
			dwStatus &= ~SCARD_ABSENT;
			dwStatus |= SCARD_SWALLOWED;
			dwStatus &= ~SCARD_POWERED;
			dwStatus &= ~SCARD_NEGOTIABLE;
			dwStatus &= ~SCARD_SPECIFIC;
			dwStatus &= ~SCARD_UNKNOWN;
			Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv);
		}

		dwCurrentState = SCARD_PRESENT;
	}
	else
	{
		dwStatus |= SCARD_ABSENT;
		dwStatus &= ~SCARD_PRESENT;
		dwStatus &= ~SCARD_POWERED;
		dwStatus &= ~SCARD_NEGOTIABLE;
		dwStatus &= ~SCARD_SPECIFIC;
		dwStatus &= ~SCARD_SWALLOWED;
		dwStatus &= ~SCARD_UNKNOWN;
		rs->xcardAtrLength(0);
		rs->xcardProtocol(SCARD_PROTOCOL_UNSET);

		dwCurrentState = SCARD_ABSENT;
	}

	/*
	 * Set all the public attributes to this reader
	 */
	rs->xreaderState(dwStatus);
	dwReaderSharing = rContext->dwContexts;
	rs->sharing(dwReaderSharing);

	SYS_MMapSynchronize((void *) rContext->readerState, pageSize);

	while (1)
	{
		dwStatus = 0;

		// Defensive measure
		if (!rContext->vHandle)
		{
			// Exit and notify the caller
			secdebug("pcscd", "EHStatusHandlerThread: lost dynamic callbacks ??");
			ReaderContextUnlock(rContext);
			SYS_ThreadDetach(rContext->pthThread);
			SYS_ThreadExit(0);
		}

		DWORD tmpCardAtrLength = MAX_ATR_SIZE;
		rv = IFDStatusICC(rContext, &dwStatus, rs->xcardAtr(), &tmpCardAtrLength);

		if (rv != SCARD_S_SUCCESS)
		{
			Log2(PCSC_LOG_ERROR, "Error communicating to: %s", lpcReader);

			/*
			 * Set error status on this reader while errors occur
			 */

			DWORD readerStateTmp = rs->xreaderState();
			readerStateTmp &= ~SCARD_ABSENT;
			readerStateTmp &= ~SCARD_PRESENT;
			readerStateTmp &= ~SCARD_POWERED;
			readerStateTmp &= ~SCARD_NEGOTIABLE;
			readerStateTmp &= ~SCARD_SPECIFIC;
			readerStateTmp &= ~SCARD_SWALLOWED;
			readerStateTmp |= SCARD_UNKNOWN;
			rs->xcardAtrLength(0);
			rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
			rs->xreaderState(readerStateTmp);

			dwCurrentState = SCARD_UNKNOWN;

			SYS_MMapSynchronize((void *) rContext->readerState, pageSize);

			/*
			 * This code causes race conditions on G4's with USB
			 * insertion
			 */
			/*
			 * dwErrorCount += 1; SYS_Sleep(1);
			 */
			/*
			 * After 10 seconds of errors, try to reinitialize the reader
			 * This sometimes helps bring readers out of *crazy* states.
			 */
			/*
			 * if ( dwErrorCount == 10 ) { RFUnInitializeReader( rContext
			 * ); RFInitializeReader( rContext ); dwErrorCount = 0; }
			 */

			/*
			 * End of race condition code block
			 */
		}

		if (dwStatus & SCARD_ABSENT)
		{
			if (dwCurrentState == SCARD_PRESENT ||
				dwCurrentState == SCARD_UNKNOWN)
			{
				/*
				 * Change the status structure
				 */
				Log2(PCSC_LOG_INFO, "Card Removed From %s", lpcReader);
				/*
				 * Notify the card has been removed
				 */
				RFSetReaderEventState(rContext, SCARD_REMOVED);

				rs->xcardAtrLength(0);
				rs->xcardProtocol(SCARD_PROTOCOL_UNSET);
				DWORD readerStateTmp = rs->xreaderState();
				readerStateTmp |= SCARD_ABSENT;
				readerStateTmp &= ~SCARD_UNKNOWN;
				readerStateTmp &= ~SCARD_PRESENT;
				readerStateTmp &= ~SCARD_POWERED;
				readerStateTmp &= ~SCARD_NEGOTIABLE;
				readerStateTmp &= ~SCARD_SWALLOWED;
				readerStateTmp &= ~SCARD_SPECIFIC;
				rs->xreaderState(readerStateTmp);
				dwCurrentState = SCARD_ABSENT;

				SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
			}

		}
		else if (dwStatus & SCARD_PRESENT)
		{
			if (dwCurrentState == SCARD_ABSENT ||
				dwCurrentState == SCARD_UNKNOWN)
			{
				/*
				 * Power and reset the card
				 */
				SYS_USleep(PCSCLITE_STATUS_WAIT);
				DWORD tmpCardAtrLength = MAX_ATR_SIZE;
				rv = IFDPowerICC(rContext, IFD_POWER_UP, rs->xcardAtr(), &tmpCardAtrLength);

				/* the protocol is unset after a power on */
				rs->xcardProtocol(SCARD_PROTOCOL_UNSET);

				secdebug("pcscd", "EHStatusHandlerThread: power-and-reset call to IFDPowerICC: %d [%04X]", rv, rv);

				DWORD readerStateTmp = rs->xreaderState();
				if (rv == IFD_SUCCESS)
				{
					rs->xcardAtrLength(tmpCardAtrLength);

					readerStateTmp |= SCARD_PRESENT;
					readerStateTmp &= ~SCARD_ABSENT;
					readerStateTmp |= SCARD_POWERED;
					readerStateTmp |= SCARD_NEGOTIABLE;
					readerStateTmp &= ~SCARD_SPECIFIC;
					readerStateTmp &= ~SCARD_UNKNOWN;
					readerStateTmp &= ~SCARD_SWALLOWED;
					rs->xreaderState(readerStateTmp);

					/*
					 * Notify the card has been reset
					 */
					RFSetReaderEventState(rContext, SCARD_RESET);
				}
				else
				{
					readerStateTmp |= SCARD_PRESENT;
					readerStateTmp &= ~SCARD_ABSENT;
					readerStateTmp |= SCARD_SWALLOWED;
					readerStateTmp &= ~SCARD_POWERED;
					readerStateTmp &= ~SCARD_NEGOTIABLE;
					readerStateTmp &= ~SCARD_SPECIFIC;
					readerStateTmp &= ~SCARD_UNKNOWN;
					rs->xreaderState(readerStateTmp);
					rs->xcardAtrLength(0);
				}

				dwCurrentState = SCARD_PRESENT;

				SYS_MMapSynchronize((void *) rContext->readerState, pageSize);

				Log2(PCSC_LOG_INFO, "Card inserted into %s", lpcReader);

				if (rv == IFD_SUCCESS)
				{
					if (rs->xcardAtrLength() > 0)
						LogXxd(PCSC_LOG_INFO, "Card ATR: ", rs->xcardAtr(), rs->xcardAtrLength());
					else
						Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
				}
				else
					Log1(PCSC_LOG_ERROR,"Error powering up card.");
			}
		}

		if (ReaderContextIsLocked(rContext))
		{
			/*
			 * Exit and notify the caller
			 */
			secdebug("pcscd", "EHStatusHandlerThread: parent requested shutdown");
			ReaderContextUnlock(rContext);
			SYS_ThreadDetach(rContext->pthThread);
			SYS_ThreadExit(0);
		}

		/*
		 * Sharing may change w/o an event pass it on
		 */

		if (dwReaderSharing != (uint32_t)rContext->dwContexts)
		{
			dwReaderSharing = rContext->dwContexts;
			rs->sharing(dwReaderSharing);
			SYS_MMapSynchronize((void *) rContext->readerState, pageSize);
		}

		SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
	}
}