Logo Search packages:      
Sourcecode: pcsc-lite version File versions  Download package

LONG SCardGetStatusChange ( SCARDCONTEXT  hContext,
DWORD  dwTimeout,
LPSCARD_READERSTATE_A  rgReaderStates,
DWORD  cReaders 
)

This function receives a structure or list of structures containing reader names. It then blocks for a change in state to occur on any of the OR'd values contained in dwCurrentState for a maximum blocking time of dwTimeout or forever if INFINITE is used.

The new event state will be contained in dwEventState. A status change might be a card insertion or removal event, a change in ATR, etc.

This function will block for reader availability if cReaders is equal to zero and rgReaderStates is NULL.

 typedef struct {
   LPCTSTR szReader;          // Reader name
   LPVOID pvUserData;         // User defined data
   DWORD dwCurrentState;      // Current state of reader
   DWORD dwEventState;        // Reader state after a state change
   DWORD cbAtr;               // ATR Length, usually MAX_ATR_SIZE
   BYTE rgbAtr[MAX_ATR_SIZE]; // ATR Value
 } SCARD_READERSTATE;
 ...
 typedef SCARD_READERSTATE *PSCARD_READERSTATE, **LPSCARD_READERSTATE;
 ...

Value of dwCurrentState and dwEventState:

  • SCARD_STATE_UNAWARE The application is unaware of the current state, and would like to know. The use of this value results in an immediate return from state transition monitoring services. This is represented by all bits set to zero.
  • SCARD_STATE_IGNORE This reader should be ignored
  • SCARD_STATE_CHANGED There is a difference between the state believed by the application, and the state known by the resource manager. When this bit is set, the application may assume a significant state change has occurred on this reader.
  • SCARD_STATE_UNKNOWN The given reader name is not recognized by the resource manager. If this bit is set, then SCARD_STATE_CHANGED and SCARD_STATE_IGNORE will also be set
  • SCARD_STATE_UNAVAILABLE The actual state of this reader is not available. If this bit is set, then all the following bits are clear.
  • SCARD_STATE_EMPTY There is no card in the reader. If this bit is set, all the following bits will be clear
  • SCARD_STATE_PRESENT There is a card in the reader
  • SCARD_STATE_ATRMATCH There is a card in the reader with an ATR matching one of the target cards. If this bit is set, SCARD_STATE_PRESENT will also be set. This bit is only returned on the SCardLocateCards function.
  • SCARD_STATE_EXCLUSIVE The card in the reader is allocated for exclusive use by another application. If this bit is set, SCARD_STATE_PRESENT will also be set.
  • SCARD_STATE_INUSE The card in the reader is in use by one or more other applications, but may be connected to in shared mode. If this bit is set, SCARD_STATE_PRESENT will also be set.
  • SCARD_STATE_MUTE There is an unresponsive card in the reader.

Parameters:
[in] hContext Connection context to the PC/SC Resource Manager.
[in] dwTimeout Maximum waiting time (in miliseconds) for status change, zero (or INFINITE) for infinite.
rgReaderStates [inout] Structures of readers with current states.
[in] cReaders Number of structures.
Returns:
Error code.
Return values:
SCARD_S_SUCCESS Successful.
SCARD_E_INVALID_VALUE Invalid States, reader name, etc.
SCARD_E_INVALID_HANDLE Invalid hContext handle.
SCARD_E_READER_UNAVAILABLE The reader is unavailable.
Test:
 SCARDCONTEXT hContext;
 SCARD_READERSTATE_A rgReaderStates[1];
 LONG rv;
 ...
 rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
 ...
 rgReaderStates[0].szReader = "Reader X";
 rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
 ...
 rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1);
 printf("reader state: 0x%04X\n", rgReaderStates[0].dwEventState);

Definition at line 688 of file winscard_scf.c.

References _psContextMap::contextBlockStatus, psContextMap, SCardGetContextIndice(), SCardLockThread(), SCardUnlockThread(), and SYS_USleep().

{

      LONG rv, retIndice, readerIndice;
      PSCARD_READERSTATE_A currReader;
      PREADER_STATE rContext;
      LPTSTR lpcReaderName;
      DWORD dwTime;
      DWORD dwState;
      DWORD dwBreakFlag;
      int i, j;

      if (SCARD_S_SUCCESS != isOCFServerRunning())
            return SCARD_E_NO_SERVICE;

      /* Zero out everything */
      rv = 0;
      rContext = 0;
      lpcReaderName = 0;
      dwTime = 0;
      j = 0;
      dwState = 0;
      i = 0;
      currReader = 0;
      retIndice = 0;
      readerIndice = 0;
      dwBreakFlag = 0;

      if (rgReaderStates == NULL && cReaders > 0)
            return SCARD_E_INVALID_PARAMETER;

      if (cReaders < 0)
            return SCARD_E_INVALID_VALUE;

      /* change by najam */
      SCardLockThread();
      retIndice = SCardGetContextIndice(hContext);
      /* change by najam */
      SCardUnlockThread();
      if (retIndice == -1)
            return SCARD_E_INVALID_HANDLE;

      /* Application is waiting for a reader -
         return the first available reader 
       */
      if (cReaders == 0)
      {
            for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
            {
                  if (psReaderMap[i].ReaderName)
                        return SCARD_S_SUCCESS;
            }
            return SCARD_E_READER_UNAVAILABLE;
      }
      else if (cReaders > PCSCLITE_MAX_READERS_CONTEXTS)
      {
            return SCARD_E_INVALID_VALUE;
      }
      /* Check the integrity of the reader states structures */
      for (j = 0; j < cReaders; j++)
      {
            currReader = &rgReaderStates[j];
            if (currReader->szReader == NULL)
            {
                  return SCARD_E_INVALID_VALUE;
            }
      }
      /* End of search for readers */

      /* Clear the event state for all readers */
      for (j = 0; j < cReaders; j++)
      {
            currReader = &rgReaderStates[j];
            currReader->dwEventState = 0;
      }

      /* Now is where we start our event checking loop */

      psContextMap[retIndice].contextBlockStatus = BLOCK_STATUS_BLOCKING;
      j = 0;

      do
      {
            SYS_USleep(10);
            if (SCARD_S_SUCCESS != isOCFServerRunning())
                  return SCARD_E_NO_SERVICE;

            currReader = &rgReaderStates[j];

      /************ Look for IGNORED readers ****************************/

            if (currReader->dwCurrentState & SCARD_STATE_IGNORE)
            {
                  currReader->dwEventState = SCARD_STATE_IGNORE;
            }
            else
            {
        /************ Looks for correct readernames *********************/

                  lpcReaderName = (char *) currReader->szReader;

                  readerIndice = SCardGetReaderIndice(lpcReaderName);
                  /* The requested reader name is not recognized */
                  if (0 > readerIndice)
                  {
                        if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
                        {
                              currReader->dwEventState = SCARD_STATE_UNKNOWN;
                        }
                        else
                        {
                              currReader->dwEventState =
                                    SCARD_STATE_UNKNOWN | SCARD_STATE_CHANGED;
                              /* Spec says use SCARD_STATE_IGNORE but a removed USB reader
                                 with eventState fed into currentState will be ignored forever */
                              dwBreakFlag = 1;
                        }
                  }
                  else
                  {
                        /* The reader has come back after being away */
                        if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
                        {
                              currReader->dwEventState |= SCARD_STATE_CHANGED;
                              currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
                              dwBreakFlag = 1;
                        }

      /*****************************************************************/
                        SCardEventLock();
                        /* Now we check all the Reader States */
                        dwState = psReaderMap[readerIndice].dwCurrentState;

      /*********** Check if the reader is in the correct state ********/
                        if (dwState & SCARD_STATE_UNKNOWN)
                        {
                              /* App thinks reader is in bad state and it is */
                              if (currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE)
                              {
                                    currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
                              }
                              else
                              {
                                    /* App thinks reader is in good state and it is not */
                                    currReader->dwEventState = SCARD_STATE_CHANGED |
                                          SCARD_STATE_UNAVAILABLE;
                                    dwBreakFlag = 1;
                              }
                        }
                        else
                        {
                              /* App thinks reader in bad state but it is not */
                              if (currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE)
                              {
                                    currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
                                    currReader->dwEventState |= SCARD_STATE_CHANGED;
                                    dwBreakFlag = 1;
                              }
                        }

      /********** Check for card presence in the reader **************/

                        if (dwState & SCARD_STATE_PRESENT)
                        {
                              currReader->cbAtr = psReaderMap[readerIndice].dwAtrLength;
                              memcpy(currReader->rgbAtr, psReaderMap[readerIndice].bAtr,
                                    currReader->cbAtr);
                        }
                        else
                        {
                              currReader->cbAtr = 0;
                        }
                        /* Card is now absent                   */
                        if (dwState & SCARD_STATE_EMPTY)
                        {
                              currReader->dwEventState |= SCARD_STATE_EMPTY;
                              currReader->dwEventState &= ~SCARD_STATE_PRESENT;
                              currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
                              currReader->dwEventState &= ~SCARD_STATE_IGNORE;
                              currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
                              currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
                              currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
                              currReader->dwEventState &= ~SCARD_STATE_MUTE;
                              currReader->dwEventState &= ~SCARD_STATE_INUSE;
                              /* After present the rest are assumed */
                              if (currReader->dwCurrentState & SCARD_STATE_PRESENT ||
                                    currReader->dwCurrentState & SCARD_STATE_ATRMATCH ||
                                    currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE ||
                                    currReader->dwCurrentState & SCARD_STATE_INUSE)
                              {
                                    currReader->dwEventState |= SCARD_STATE_CHANGED;
                                    dwBreakFlag = 1;
                              }
                              /* Card is now present              */
                        }
                        else if (dwState & SCARD_STATE_PRESENT)
                        {
                              currReader->dwEventState |= SCARD_STATE_PRESENT;
                              currReader->dwEventState &= ~SCARD_STATE_EMPTY;
                              currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
                              currReader->dwEventState &= ~SCARD_STATE_IGNORE;
                              currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
                              currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
                              currReader->dwEventState &= ~SCARD_STATE_MUTE;

                              if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
                              {
                                    currReader->dwEventState |= SCARD_STATE_CHANGED;
                                    dwBreakFlag = 1;
                              }
                              /* TODO */
                              if (0 && dwState & SCARD_SWALLOWED)
                              {
                                    if (currReader->dwCurrentState & SCARD_STATE_MUTE)
                                    {
                                          currReader->dwEventState |= SCARD_STATE_MUTE;
                                    }
                                    else
                                    {
                                          currReader->dwEventState |= SCARD_STATE_MUTE;
                                          if (currReader->dwCurrentState !=
                                                SCARD_STATE_UNAWARE)
                                          {
                                                currReader->dwEventState |=
                                                      SCARD_STATE_CHANGED;
                                          }
                                          dwBreakFlag = 1;
                                    }
                              }
                              else
                              {
                                    /* App thinks card is mute but it is not */
                                    if (currReader->dwCurrentState & SCARD_STATE_MUTE)
                                    {
                                          currReader->dwEventState |= SCARD_STATE_CHANGED;
                                          dwBreakFlag = 1;
                                    }
                              }
                        }

                        if (-1 == psReaderMap[readerIndice].SharedRefCount)
                        {
                              currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
                              currReader->dwEventState &= ~SCARD_STATE_INUSE;
                              if (!currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE)
                              {
                                    currReader->dwEventState |= SCARD_STATE_CHANGED;
                                    dwBreakFlag = 1;
                              }
                        }
                        else if (psReaderMap[readerIndice].SharedRefCount >= 1)
                        {
                              /* A card must be inserted for it to be INUSE */
                              if (dwState & SCARD_STATE_PRESENT)
                              {
                                    currReader->dwEventState |= SCARD_STATE_INUSE;
                                    currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
                                    if (!currReader->dwCurrentState & SCARD_STATE_INUSE)
                                    {
                                          currReader->dwEventState |= SCARD_STATE_CHANGED;
                                          dwBreakFlag = 1;
                                    }
                              }
                        }
                        SCardEventUnlock();
                        if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
                        {
                              /* Break out of the while .. loop and return status 
                                 once all the status's for all readers is met */
                              dwBreakFlag = 1;
                        }
                        SYS_USleep(PCSCLITE_STATUS_WAIT);

                  }                             /* End of SCARD_STATE_UNKNOWN */

            }                                   /* End of SCARD_STATE_IGNORE */

            /* Counter and resetter */
            j = j + 1;
            if (j == cReaders)
                  j = 0;

            if (dwTimeout != INFINITE && dwTimeout != 0)
            {
                  dwTime += PCSCLITE_STATUS_WAIT;

                  /* If time is greater than timeout and all readers have been 
                     checked
                   */
                  if ((dwTime >= (dwTimeout * 1000)) && (j == 0))
                  {
                        return SCARD_E_TIMEOUT;
                  }
            }

            /* Declare all the break conditions */
            /* TODO think about this */
            if (psContextMap[retIndice].contextBlockStatus == BLOCK_STATUS_RESUME)
                  break;

            /* Break if UNAWARE is set and all readers have been checked */
            if ((dwBreakFlag == 1) && (j == 0))
                  break;

            /*
             * Solve the problem of never exiting the loop when a smartcard is
             * already inserted in the reader, thus blocking the application
             * (patch proposed by Serge Koganovitsch)
             */
            if ((dwTimeout == 0) && (j == 0))
                  break;

      }
      while (1);                          /* end of do */

      if (psContextMap[retIndice].contextBlockStatus == BLOCK_STATUS_RESUME)
      {
            return SCARD_E_CANCELLED;
      }

      return SCARD_S_SUCCESS;
}


Generated by  Doxygen 1.6.0   Back to index