[Pcsclite-cvs-commit] r5328 - in /trunk/PCSC: TODO src/PCSC/ifdhandler.h src/eventhandler.c src/eventhandler.h src/pcscd.h.in src/readerfactory.c src/readerfactory.h src/winscard.c

rousseau at users.alioth.debian.org rousseau at users.alioth.debian.org
Thu Oct 21 18:50:34 UTC 2010


Author: rousseau
Date: Thu Oct 21 18:50:24 2010
New Revision: 5328

URL: http://svn.debian.org/wsvn/pcsclite/?sc=1&rev=5328
Log:
Power on the card _only_ if an application requests a connection
see Alioth bug #301965 

You can disable the feature using DISABLE_ON_DEMAND_POWER_ON in
src/eventhandler.c

Modified:
    trunk/PCSC/TODO
    trunk/PCSC/src/PCSC/ifdhandler.h
    trunk/PCSC/src/eventhandler.c
    trunk/PCSC/src/eventhandler.h
    trunk/PCSC/src/pcscd.h.in
    trunk/PCSC/src/readerfactory.c
    trunk/PCSC/src/readerfactory.h
    trunk/PCSC/src/winscard.c

Modified: trunk/PCSC/TODO
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/TODO?rev=5328&op=diff
==============================================================================
--- trunk/PCSC/TODO (original)
+++ trunk/PCSC/TODO Thu Oct 21 18:50:24 2010
@@ -1,9 +1,4 @@
 - include Apple patches and improvements (if possible/needed)
-
-- power on the card _only_ if an application requests a connection
-  see Alioth bug #301965
-  That could be implemented by polling the reader only if an application
-  requests it.
 
 - allow to have pcscd and libpcsclite on two different machines.
   That would be needed to support remote PAM login.
@@ -30,4 +25,4 @@
 
 - use static driver instead of reader polling and dynamic driver loading
 
-March 2010
+October 2010

Modified: trunk/PCSC/src/PCSC/ifdhandler.h
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/PCSC/ifdhandler.h?rev=5328&op=diff
==============================================================================
--- trunk/PCSC/src/PCSC/ifdhandler.h (original)
+++ trunk/PCSC/src/PCSC/ifdhandler.h Thu Oct 21 18:50:24 2010
@@ -307,9 +307,10 @@
 #define TAG_IFD_THREAD_SAFE             0x0FAD	/**< driver is thread safe */
 #define TAG_IFD_SLOTS_NUMBER            0x0FAE	/**< number of slots of the reader */
 #define TAG_IFD_SIMULTANEOUS_ACCESS     0x0FAF	/**< number of reader the driver can manage */
-#define TAG_IFD_POLLING_THREAD          0x0FB0	/**< driver uses a polling thread */
+#define TAG_IFD_POLLING_THREAD          0x0FB0	/**< not used. See TAG_IFD_POLLING_THREAD_WITH_TIMEOUT */
 #define TAG_IFD_POLLING_THREAD_KILLABLE 0x0FB1	/**< the polling thread can be killed */
 #define TAG_IFD_STOP_POLLING_THREAD     0x0FB2	/**< method used to stop the polling thread (instead of just pthread_kill()) */
+#define TAG_IFD_POLLING_THREAD_WITH_TIMEOUT 0x0FB3	/**< driver uses a polling thread with a timeout parameter */
 
 	/*
 	 * IFD Handler version number enummerations

Modified: trunk/PCSC/src/eventhandler.c
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/eventhandler.c?rev=5328&op=diff
==============================================================================
--- trunk/PCSC/src/eventhandler.c (original)
+++ trunk/PCSC/src/eventhandler.c Thu Oct 21 18:50:24 2010
@@ -39,6 +39,9 @@
 #include "winscard_svc.h"
 #include "simclist.h"
 
+/* Uncomment the next line if you do NOT want to use auto power off */
+/* #define DISABLE_ON_DEMAND_POWER_ON */
+
 static list_t ClientsWaitingForEvent;	/**< list of client file descriptors */
 pthread_mutex_t ClientsWaitingForEvent_lock;	/**< lock for the above list */
 
@@ -204,8 +207,7 @@
 	return SCARD_S_SUCCESS;
 }
 
-LONG EHSpawnEventHandler(READER_CONTEXT * rContext,
-	RESPONSECODE (*card_event)(DWORD))
+LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
 {
 	LONG rv;
 	DWORD dwStatus = 0;
@@ -218,7 +220,6 @@
 		return SCARD_F_UNKNOWN_ERROR;
 	}
 
-	rContext->pthCardEvent = card_event;
 	rv = ThreadCreate(&rContext->pthThread, 0,
 		(PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
 	if (rv)
@@ -264,6 +265,7 @@
 		if (rv == IFD_SUCCESS)
 		{
 			readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
+			rContext->powerState = POWER_STATE_POWERED;
 
 			if (rContext->readerState->cardAtrLength > 0)
 			{
@@ -277,6 +279,7 @@
 		else
 		{
 			readerState = SCARD_PRESENT | SCARD_SWALLOWED;
+			rContext->powerState = POWER_STATE_UNPOWERED;
 			Log3(PCSC_LOG_ERROR, "Error powering up card: %d 0x%04X", rv, rv);
 		}
 
@@ -365,10 +368,12 @@
 				if (rv == IFD_SUCCESS)
 				{
 					rContext->readerState->readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
+					rContext->powerState = POWER_STATE_POWERED;
 				}
 				else
 				{
 					rContext->readerState->readerState = SCARD_PRESENT | SCARD_SWALLOWED;
+					rContext->powerState = POWER_STATE_UNPOWERED;
 					rContext->readerState->cardAtrLength = 0;
 				}
 
@@ -409,13 +414,42 @@
 		if (rContext->pthCardEvent)
 		{
 			int ret;
-
-			ret = rContext->pthCardEvent(rContext->slot);
+			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_NO_SUCH_DEVICE == 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 */
+		if (POWER_STATE_POWERED == rContext->powerState)
+		{
+			/* power down */
+			IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
+			rContext->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;
+#endif
 
 		if (rContext->hLockId == 0xFFFF)
 		{

Modified: trunk/PCSC/src/eventhandler.h
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/eventhandler.h?rev=5328&op=diff
==============================================================================
--- trunk/PCSC/src/eventhandler.h (original)
+++ trunk/PCSC/src/eventhandler.h Thu Oct 21 18:50:24 2010
@@ -47,8 +47,7 @@
 	LONG EHUnregisterClientForEvent(int32_t filedes); 
 	LONG EHSignalEventToClients(void);
 	LONG EHInitializeEventStructures(void);
-	LONG EHSpawnEventHandler(READER_CONTEXT *,
-		/*@null@*/ RESPONSECODE (*)(DWORD));
+	LONG EHSpawnEventHandler(READER_CONTEXT *);
 	LONG EHDestroyEventHandler(READER_CONTEXT *);
 
 /** One application is using the reader */

Modified: trunk/PCSC/src/pcscd.h.in
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/pcscd.h.in?rev=5328&op=diff
==============================================================================
--- trunk/PCSC/src/pcscd.h.in (original)
+++ trunk/PCSC/src/pcscd.h.in Thu Oct 21 18:50:24 2010
@@ -46,4 +46,20 @@
 #define MAX_BUFFER_SIZE			264	/**< Maximum Tx/Rx Buffer for get/set attributes */
 #define MAX_BUFFER_SIZE_EXTENDED	(4 + 3 + (1<<16) + 3)	/**< max APDU (64K + APDU + Lc + Le) Tx/Rx Buffer */
 
+/** Different values for struct ReaderContext powerState field */
+enum
+{
+	POWER_STATE_UNPOWERED,	/**< auto power off */
+	POWER_STATE_POWERED,	/**< powered */
+	POWER_STATE_GRACE_PERIOD,	/**< card was in use */
+	POWER_STATE_INUSE		/**< card is used */
+};
+
+/** time to wait before powering down an unused card */
+#define PCSCLITE_POWER_OFF_GRACE_PERIOD 5*1000 /* 5 second */
+
+/** normal timeout for pthCardEvent driver function when
+ * no card or card in use */
+#define PCSCLITE_STATUS_EVENT_TIMEOUT 10*60*1000 /* 10 minutes */
+
 #endif

Modified: trunk/PCSC/src/readerfactory.c
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/readerfactory.c?rev=5328&op=diff
==============================================================================
--- trunk/PCSC/src/readerfactory.c (original)
+++ trunk/PCSC/src/readerfactory.c Thu Oct 21 18:50:24 2010
@@ -185,6 +185,7 @@
 	(sReadersContexts[dwContext])->vHandle = NULL;
 	(sReadersContexts[dwContext])->pFeeds = NULL;
 	(sReadersContexts[dwContext])->pMutex = NULL;
+	sReadersContexts[dwContext]->pthCardEvent = NULL;
 	(sReadersContexts[dwContext])->dwIdentity =
 		(dwContext + 1) << IDENTITY_SHIFT;
 
@@ -272,21 +273,23 @@
 
 	/* asynchronous card movement?  */
 	{
-		RESPONSECODE (*fct)(DWORD) = NULL;
+		RESPONSECODE (*fct)(DWORD, int) = NULL;
 
 		dwGetSize = sizeof(fct);
 
 		rv = IFDGetCapabilities((sReadersContexts[dwContext]),
-			TAG_IFD_POLLING_THREAD, &dwGetSize, (PUCHAR)&fct);
+			TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct);
 		if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct)))
 		{
-			fct = NULL;
 			Log1(PCSC_LOG_INFO, "Using the pcscd polling thread");
 		}
 		else
+		{
+			sReadersContexts[dwContext]->pthCardEvent = fct;
 			Log1(PCSC_LOG_INFO, "Using the reader polling thread");
-
-		rv = EHSpawnEventHandler(sReadersContexts[dwContext], fct);
+		}
+
+		rv = EHSpawnEventHandler(sReadersContexts[dwContext]);
 		if (rv != SCARD_S_SUCCESS)
 		{
 			Log2(PCSC_LOG_ERROR, "%s init failed.", readerName);
@@ -319,7 +322,7 @@
 	{
 		char *tmpReader = NULL;
 		DWORD dwContextB = 0;
-		RESPONSECODE (*fct)(DWORD) = NULL;
+		RESPONSECODE (*fct)(DWORD, int) = NULL;
 
 		/* We must find an empty spot to put the reader structure */
 		for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
@@ -428,16 +431,18 @@
 		dwGetSize = sizeof(fct);
 
 		rv = IFDGetCapabilities((sReadersContexts[dwContextB]),
-				TAG_IFD_POLLING_THREAD, &dwGetSize, (PUCHAR)&fct);
+			TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct);
 		if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct)))
 		{
-			fct = NULL;
 			Log1(PCSC_LOG_INFO, "Using the pcscd polling thread");
 		}
 		else
+		{
+			sReadersContexts[dwContextB]->pthCardEvent = fct;
 			Log1(PCSC_LOG_INFO, "Using the reader polling thread");
-
-		rv = EHSpawnEventHandler(sReadersContexts[dwContextB], fct);
+		}
+
+		rv = EHSpawnEventHandler(sReadersContexts[dwContextB]);
 		if (rv != SCARD_S_SUCCESS)
 		{
 			Log2(PCSC_LOG_ERROR, "%s init failed.", readerName);

Modified: trunk/PCSC/src/readerfactory.h
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/readerfactory.h?rev=5328&op=diff
==============================================================================
--- trunk/PCSC/src/readerfactory.h (original)
+++ trunk/PCSC/src/readerfactory.h Thu Oct 21 18:50:24 2010
@@ -108,7 +108,7 @@
 		char *library;	/**< Library Path */
 		char *device;	/**< Device Name */
 		pthread_t pthThread;	/**< Event polling thread */
-		RESPONSECODE (*pthCardEvent)(DWORD);	/**< Card Event sync */
+		RESPONSECODE (*pthCardEvent)(DWORD, int);	/**< Card Event sync */
 		pthread_mutex_t *mMutex;	/**< Mutex for this connection */
 		list_t handlesList;
 		pthread_mutex_t handlesList_lock;	/**< lock for the above list */
@@ -129,6 +129,7 @@
 		int32_t contexts;		/**< Number of open contexts */
 		int * pFeeds;			/**< Number of shared client to lib */
 		int * pMutex;			/**< Number of client to mutex */
+		int powerState;			/**< auto power off state */
 
 		struct pubReaderStatesList *readerState; /**< link to the reader state */
 		/* we can't use READER_CONTEXT * here since eventhandler.h can't be

Modified: trunk/PCSC/src/winscard.c
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/winscard.c?rev=5328&op=diff
==============================================================================
--- trunk/PCSC/src/winscard.c (original)
+++ trunk/PCSC/src/winscard.c Thu Oct 21 18:50:24 2010
@@ -342,6 +342,20 @@
 		}
 	}
 
+	/* Power on (again) the card if needed */
+	if (POWER_STATE_UNPOWERED == rContext->powerState)
+	{
+		DWORD dwAtrLen;
+
+		dwAtrLen = sizeof(rContext->readerState->cardAtr);
+		Log0(PCSC_LOG_CRITICAL);
+		rv = IFDPowerICC(rContext, IFD_POWER_UP,
+			rContext->readerState->cardAtr, &dwAtrLen);
+		rContext->readerState->cardAtrLength = dwAtrLen;
+	}
+
+	/* the card is now in use */
+	rContext->powerState = POWER_STATE_INUSE;
 
 	/*******************************************
 	 *
@@ -943,6 +957,26 @@
 			rContext->contexts = 0;
 	}
 
+	if (PCSCLITE_SHARING_NO_CONTEXT == rContext->contexts)
+	{
+		RESPONSECODE (*fct)(DWORD) = NULL;
+		DWORD dwGetSize;
+
+		rContext->powerState = POWER_STATE_GRACE_PERIOD;
+
+		/* ask to stop the "polling" thread so it can be restarted using
+		 * the correct timeout */
+		dwGetSize = sizeof(fct);
+		rv = IFDGetCapabilities(rContext, TAG_IFD_STOP_POLLING_THREAD,
+			&dwGetSize, (PUCHAR)&fct);
+
+		if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
+		{
+			Log1(PCSC_LOG_INFO, "Stoping polling thread");
+			fct(rContext->slot);
+		}
+	}
+
 	/*
 	 * Propagate new state to reader state
 	 */




More information about the Pcsclite-cvs-commit mailing list