Exemplo n.º 1
0
LONG IFDControl(READER_CONTEXT * rContext, DWORD ControlCode,
	LPCVOID TxBuffer, DWORD TxLength, LPVOID RxBuffer, DWORD RxLength,
	LPDWORD BytesReturned)
{
	RESPONSECODE rv = IFD_SUCCESS;

#ifndef PCSCLITE_STATIC_DRIVER
	RESPONSECODE(*IFDH_control) (DWORD, DWORD, LPCVOID, DWORD, LPVOID, DWORD, LPDWORD);
#endif

	if (rContext->version < IFD_HVERSION_3_0)
		return SCARD_E_UNSUPPORTED_FEATURE;

#ifndef PCSCLITE_STATIC_DRIVER
	IFDH_control = rContext->psFunctions.psFunctions_v3.pvfControl;
#endif

	/* LOCK THIS CODE REGION */
	(void)pthread_mutex_lock(rContext->mMutex);

#ifndef PCSCLITE_STATIC_DRIVER
	rv = (*IFDH_control) (rContext->slot, ControlCode, TxBuffer,
		TxLength, RxBuffer, RxLength, BytesReturned);
#elif defined(IFDHANDLERv3)
	rv = IFDHControl(rContext->slot, ControlCode, TxBuffer,
		TxLength, RxBuffer, RxLength, BytesReturned);
#endif

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

	if (rv == IFD_SUCCESS)
		return SCARD_S_SUCCESS;
	else
	{
		Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
		Log3(PCSC_LOG_DEBUG, "ControlCode: 0x%.8lX BytesReturned: %ld",
			ControlCode, *BytesReturned);
		LogXxd(PCSC_LOG_DEBUG, "TxBuffer ", TxBuffer, TxLength);
		LogXxd(PCSC_LOG_DEBUG, "RxBuffer ", RxBuffer, *BytesReturned);

		if (rv == IFD_NO_SUCH_DEVICE)
		{
			(void)SendHotplugSignal();
			return SCARD_E_READER_UNAVAILABLE;
		}

		if ((IFD_ERROR_NOT_SUPPORTED == rv) || (IFD_NOT_SUPPORTED == rv))
			return SCARD_E_UNSUPPORTED_FEATURE;

        if (IFD_ERROR_INSUFFICIENT_BUFFER ==rv)
            return SCARD_E_INSUFFICIENT_BUFFER;

		return SCARD_E_NOT_TRANSACTED;
	}
}
Exemplo n.º 2
0
LONG IFDControl(PREADER_CONTEXT rContext, DWORD ControlCode,
	LPCVOID TxBuffer, DWORD TxLength, LPVOID RxBuffer, DWORD RxLength,
	LPDWORD BytesReturned)
{
	RESPONSECODE rv = IFD_SUCCESS;

#ifndef PCSCLITE_STATIC_DRIVER
	RESPONSECODE(*IFDH_control) (DWORD, DWORD, LPCVOID, DWORD, LPVOID, DWORD, LPDWORD);
#endif

	if (rContext->dwVersion < IFD_HVERSION_3_0)
		return SCARD_E_UNSUPPORTED_FEATURE;

#ifndef PCSCLITE_STATIC_DRIVER
	IFDH_control = rContext->psFunctions.psFunctions_v3.pvfControl;
#endif

	/* LOCK THIS CODE REGION */
	(void)SYS_MutexLock(rContext->mMutex);

#ifndef PCSCLITE_STATIC_DRIVER
	rv = (*IFDH_control) (rContext->dwSlot, ControlCode, TxBuffer,
		TxLength, RxBuffer, RxLength, BytesReturned);
#else
	rv = IFDHControl(rContext->dwSlot, ControlCode, TxBuffer,
		TxLength, RxBuffer, RxLength, BytesReturned);
#endif

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

	if (rv == IFD_SUCCESS)
		return SCARD_S_SUCCESS;
	else
	{
		Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
		Log3(PCSC_LOG_DEBUG, "ControlCode: 0x%.8LX BytesReturned: %ld",
			ControlCode, *BytesReturned);
		LogXxd(PCSC_LOG_DEBUG, "TxBuffer ", TxBuffer, TxLength);
		LogXxd(PCSC_LOG_DEBUG, "RxBuffer ", RxBuffer, *BytesReturned);

		if (rv == IFD_NO_SUCH_DEVICE)
		{
//			(void)SendHotplugSignal();
			return SCARD_E_READER_UNAVAILABLE;
		}

		return SCARD_E_NOT_TRANSACTED;
	}
}
Exemplo n.º 3
0
LONG IFDControl_v2(PREADER_CONTEXT rContext, PUCHAR TxBuffer,
	DWORD TxLength, PUCHAR RxBuffer, PDWORD RxLength)
{
	RESPONSECODE rv = IFD_SUCCESS;

#ifndef PCSCLITE_STATIC_DRIVER
	RESPONSECODE(*IFDH_control_v2) (DWORD, PUCHAR, DWORD, /*@out@*/ PUCHAR,
		PDWORD);
#endif

	if (rContext->dwVersion != IFD_HVERSION_2_0)
		return SCARD_E_UNSUPPORTED_FEATURE;

#ifndef PCSCLITE_STATIC_DRIVER
	IFDH_control_v2 = rContext->psFunctions.psFunctions_v2.pvfControl;
#endif

	/* LOCK THIS CODE REGION */
	(void)SYS_MutexLock(rContext->mMutex);

#ifndef PCSCLITE_STATIC_DRIVER
	rv = (*IFDH_control_v2) (rContext->dwSlot, TxBuffer, TxLength,
		RxBuffer, RxLength);
#else
	rv = IFDHControl_v2(rContext->dwSlot, TxBuffer, TxLength,
		RxBuffer, RxLength);
#endif

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

	if (rv == IFD_SUCCESS)
		return SCARD_S_SUCCESS;
	else
	{
		Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
		LogXxd(PCSC_LOG_DEBUG, "TxBuffer ", TxBuffer, TxLength);
		LogXxd(PCSC_LOG_DEBUG, "RxBuffer ", RxBuffer, *RxLength);
		return SCARD_E_NOT_TRANSACTED;
	}
}
Exemplo n.º 4
0
int get_atr(enum atr_modulation modulation,
            const unsigned char *in, size_t inlen,
            unsigned char *atr, size_t *atr_len)
{
  unsigned char hb[0xff - 1], tck;
  size_t hb_len, idx, len;

  if (!in || !atr_len)
    return 0;

  /* get the Historical Bytes */
  switch (modulation) {
    case ATR_ISO14443A_106:
      LogXxd(PCSC_LOG_DEBUG, "Will calculate ATR from this ATS payload: ",
             in, inlen);

      if (inlen) {
        idx = 1;

        /* Bits 5 to 7 tell if TA1/TB1/TC1 are available */
        if (in[0] & 0x10) { // TA
          idx++;
        }
        if (in[0] & 0x20) { // TB
          idx++;
        }
        if (in[0] & 0x40) { // TC
          idx++;
        }

        if (idx < inlen) {
          hb_len = inlen - idx;
          memcpy(hb, in + idx, hb_len);

          Log3(PCSC_LOG_DEBUG, "Found %zu interface byte(s)"
               " and %zu historical byte(s)",
               idx - 2, hb_len);
        } else {
          hb_len = 0;
        }
      } else {
        hb_len = 0;
      }
      break;
    case ATR_ISO14443B_106:
      LogXxd(PCSC_LOG_DEBUG, "Will calculate ATR from this ATQB: ",
             in, inlen);
      if (inlen < 12) {
        Log1(PCSC_LOG_INFO, "ATQB too short "
             "to contain historical bytes");
        hb_len = 0;
        break;
      }
      memcpy(hb, in + 5, 7);
      hb[7] = 0;
      hb_len = 8;
      break;
    case ATR_DEFAULT:
      hb_len = 0;
      break;
    default:
      /* for all other types: Empty ATR */
      Log1(PCSC_LOG_INFO, "Returning empty ATR "
           "for card without APDU support.");
      *atr_len = 0;
      return 1;
  }

  /* length of ATR without TCK */
  len = 4 + hb_len;

  if (*atr_len < len + 1)
    return 0;

  atr[0] = 0x3b;
  atr[1] = 0x80 + hb_len;
  atr[2] = 0x80;
  atr[3] = 0x01;
  memcpy(&atr[4], hb, hb_len);

  /* calculate TCK */
  tck = atr[1];
  for (idx = 2; idx < len; idx++) {
    tck ^= atr[idx];
  }

  atr[len] = tck;

  *atr_len = len + 1;

  return 1;
}
Exemplo n.º 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);
		}
	}
}
Exemplo n.º 6
0
/**
 * @brief parse an ATR
 *
 * @param[out] psExtension
 * @param[in] pucAtr ATR
 * @param[in] dwLength ATR length
 * @return
 */
short ATRDecodeAtr(PSMARTCARD_EXTENSION psExtension,
	const unsigned char *pucAtr, DWORD dwLength)
{
	USHORT p;
	UCHAR K, TCK;				/* MSN of T0/Check Sum */
	UCHAR Y1i, T;				/* MSN/LSN of TDi */
	int i = 1;					/* value of the index in TAi, TBi, etc. */

	/*
	 * Zero out everything 
	 */
	p = K = TCK = Y1i = T = 0;

#ifdef ATR_DEBUG
	if (dwLength > 0)
		LogXxd(PCSC_LOG_DEBUG, "ATR: ", pucAtr, dwLength);
#endif

	if (dwLength < 2)
		return 0;	/** @retval 0 Atr must have TS and T0 */

	/*
	 * Zero out the bitmasks 
	 */
	psExtension->CardCapabilities.AvailableProtocols = SCARD_PROTOCOL_UNDEFINED;
	psExtension->CardCapabilities.CurrentProtocol = SCARD_PROTOCOL_UNDEFINED;

	/*
	 * Decode the TS byte 
	 */
	if (pucAtr[0] == 0x3F)
	{	/* Inverse convention used */
		psExtension->CardCapabilities.Convention = SCARD_CONVENTION_INVERSE;
	}
	else
		if (pucAtr[0] == 0x3B)
	{	/* Direct convention used */
		psExtension->CardCapabilities.Convention = SCARD_CONVENTION_DIRECT;
		}
		else
	{
		memset(psExtension, 0x00, sizeof(SMARTCARD_EXTENSION));
			return 0;	/** @retval 0 Unable to decode TS byte */
	}

	/*
	 * Here comes the platform dependant stuff 
	 */

	/*
	 * Decode the T0 byte 
	 */
	Y1i = pucAtr[1] >> 4;	/* Get the MSN in Y1 */
	K = pucAtr[1] & 0x0F;	/* Get the LSN in K */

	p = 2;

#ifdef ATR_DEBUG
	Log4(PCSC_LOG_DEBUG, "Conv: %02X, Y1: %02X, K: %02X",
		psExtension->CardCapabilities.Convention, Y1i, K);
#endif

	/*
	 * Examine Y1 
	 */
	do
	{
		short TAi, TBi, TCi, TDi;	/* Interface characters */

		TAi = (Y1i & 0x01) ? pucAtr[p++] : -1;
		TBi = (Y1i & 0x02) ? pucAtr[p++] : -1;
		TCi = (Y1i & 0x04) ? pucAtr[p++] : -1;
		TDi = (Y1i & 0x08) ? pucAtr[p++] : -1;

#ifdef ATR_DEBUG
		Log9(PCSC_LOG_DEBUG,
			"TA%d: %02X, TB%d: %02X, TC%d: %02X, TD%d: %02X",
			i, TAi, i, TBi, i, TCi, i, TDi);
#endif

		/*
		 * Examine TDi to determine protocol and more 
		 */
		if (TDi >= 0)
		{
			Y1i = TDi >> 4;	/* Get the MSN in Y1 */
			T = TDi & 0x0F;	/* Get the LSN in K */

			/*
			 * Set the current protocol TD1 (first TD only)
			 */
			if (psExtension->CardCapabilities.CurrentProtocol == SCARD_PROTOCOL_UNDEFINED)
			{
				switch (T)
				{
				case 0:
					psExtension->CardCapabilities.CurrentProtocol =
						SCARD_PROTOCOL_T0;
					break;
				case 1:
					psExtension->CardCapabilities.CurrentProtocol =
						SCARD_PROTOCOL_T1;
					break;
				default:
						return 0; /** @retval 0 Unable to decode LNS */
				}
			}

#ifdef ATR_DEBUG
			Log2(PCSC_LOG_DEBUG, "T=%d Protocol Found", T);
#endif
			if (0 == T)
			{
				psExtension->CardCapabilities.AvailableProtocols |=
					SCARD_PROTOCOL_T0;
			}
			else
				if (1 == T)
			{
				psExtension->CardCapabilities.AvailableProtocols |=
					SCARD_PROTOCOL_T1;
				}
				else
					if (15 == T)
			{
						psExtension->CardCapabilities.AvailableProtocols |=
							SCARD_PROTOCOL_T15;
					}
					else
					{
				/*
				 * Do nothing for now since other protocols are not
				 * supported at this time 
				 */
			}
		} else
			Y1i = 0;

		/* test presence of TA2 */
		if ((2 == i) && (TAi >= 0))
		{
			T = TAi & 0x0F;
#ifdef ATR_DEBUG
			Log2(PCSC_LOG_DEBUG, "Specific mode: T=%d", T);
#endif
			switch (T)
			{
				case 0:
					psExtension->CardCapabilities.CurrentProtocol =
						psExtension->CardCapabilities.AvailableProtocols =
						SCARD_PROTOCOL_T0;
					break;

				case 1:
					psExtension->CardCapabilities.CurrentProtocol =
						psExtension->CardCapabilities.AvailableProtocols =
						SCARD_PROTOCOL_T1;
					break;

				default:
					return 0; /** @retval 0 Unable do decode T protocol */
		}
		}

		if (p > MAX_ATR_SIZE)
		{
			memset(psExtension, 0x00, sizeof(SMARTCARD_EXTENSION));
			return 0;	/** @retval 0 Maximum attribute size */
		}

		/* next interface characters index */
		i++;
	}
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);
	}
}