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
This commit is contained in:
James Tavares 2022-11-14 00:21:12 -05:00 committed by laforge
parent f75843d9d2
commit f74d1dab7a
2 changed files with 28 additions and 4 deletions

View File

@ -96,6 +96,12 @@ struct bankd_worker {
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 */

View File

@ -115,6 +115,8 @@ static struct bankd_worker *bankd_create_worker(struct bankd *bankd, unsigned in
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 @@ static int worker_handle_clientSlotStatusInd(struct bankd_worker *worker, const
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;
}