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;
}