bankd: edge detect RESET and VCC indications

- perform edge detection on RESET and VCC client indications to filter
out duplicate resets
- prior to this change, unrelated changes in the client slot status
indication (such as CLK change) could trigger duplicate resets
- these resets could happen in rapid succession and lead to reader
libusb communication errors that lock-up the PC/SC daemon
- a drop in VCC will always induce a cold reset, even if a warm
reset is already in progress.
- overall, this change better matches what the hardware would do

Change-Id: I36d30d176c0a03d97554112ca712d658d986c752
diff --git a/src/bankd/bankd.h b/src/bankd/bankd.h
index 0f94818..e340b5a 100644
--- a/src/bankd/bankd.h
+++ b/src/bankd/bankd.h
@@ -96,6 +96,12 @@
 		uint8_t atr[MAX_ATR_SIZE];
 		unsigned int atr_len;
 	} card;
+
+	/* last known state of the SIM card VCC indication */
+	bool last_vccPresent;
+
+	/* last known state of the SIM card reset indication */
+	bool last_resetActive;
 };
 
 /* bankd card reader driver operations */
diff --git a/src/bankd/bankd_main.c b/src/bankd/bankd_main.c
index e184aba..bf7ca82 100644
--- a/src/bankd/bankd_main.c
+++ b/src/bankd/bankd_main.c
@@ -115,6 +115,8 @@
 	worker->bankd = bankd;
 	worker->num = i;
 	worker->ops = &pcsc_driver_ops;
+	worker->last_vccPresent = true; /* allow cold reset should first indication be false */
+	worker->last_resetActive = false; /* allow warm reset should first indication be true */
 
 	/* in the initial state, the worker has no client.fd, bank_slot or pcsc handle yet */
 
@@ -774,10 +776,26 @@
 		sps->clkActive ? *sps->clkActive ? "ACTIVE" : "INACTIVE" : "NULL");
 
 	/* perform cold or warm reset */
-	if (sps->vccPresent && *sps->vccPresent == 0)
-		rc = worker->ops->reset_card(worker, true);
-	else if (sps->resetActive)
-		rc = worker->ops->reset_card(worker, false);
+	if (sps->vccPresent && *sps->vccPresent == 0) {
+		/* VCC is not present */
+
+		if (worker->last_vccPresent) {
+			/* falling edge detected on VCC; perform cold reset */
+			rc = worker->ops->reset_card(worker, true);
+		}
+	} else if (sps->resetActive) {
+		if (!worker->last_resetActive) {
+			/* VCC is present (or not reported) and rising edge detected on reset; perform warm reset */
+			rc = worker->ops->reset_card(worker, false);
+		}
+	}
+
+	/* update last known states */
+	if (sps->vccPresent) {
+		worker->last_vccPresent = *sps->vccPresent != 0;
+	}
+
+	worker->last_resetActive = sps->resetActive != 0;
 
 	return rc;
 }