From 8be396fee3d344678349529172a396de22d92087 Mon Sep 17 00:00:00 2001 From: nils Date: Wed, 22 Mar 2006 21:44:09 +0000 Subject: [PATCH] =?UTF-8?q?add=20function=20sc=5Freset()=20to=20reset=20a?= =?UTF-8?q?=20card;=20patch=20supplied=20by=20Josep=20Mon=C3=A9s=20Teixido?= =?UTF-8?q?r=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@2877 c6295689-39f2-0310-b995-f0e70906c6a9 --- src/libopensc/card.c | 27 ++++++++++++++++++++++++++ src/libopensc/opensc.h | 9 +++++++++ src/libopensc/reader-pcsc.c | 38 ++++++++++++++++++++++++++++++++++--- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/libopensc/card.c b/src/libopensc/card.c index 7efff171..c2d171bc 100644 --- a/src/libopensc/card.c +++ b/src/libopensc/card.c @@ -249,6 +249,33 @@ int sc_disconnect_card(sc_card_t *card, int action) SC_FUNC_RETURN(ctx, 1, 0); } +int sc_reset(sc_card_t *card) +{ + int r, r2; + + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + if (card->reader->ops->reset == NULL) + return SC_ERROR_NOT_SUPPORTED; + + r = sc_mutex_lock(card->ctx, card->mutex); + if (r != SC_SUCCESS) + return r; + + r = card->reader->ops->reset(card->reader, card->slot); + /* invalidate cache */ + memset(&card->cache, 0, sizeof(card->cache)); + card->cache_valid = 0; + + r2 = sc_mutex_unlock(card->ctx, card->mutex); + if (r2 != SC_SUCCESS) { + sc_error(card->ctx, "unable to release lock\n"); + r = r != SC_SUCCESS ? r : r2; + } + + return r; +} + int sc_lock(sc_card_t *card) { int r = 0; diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 386b85f1..af3f3ecf 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -394,6 +394,7 @@ struct sc_reader_operations { int *reader_index, unsigned int *event, int timeout); + int (*reset)(struct sc_reader *, struct sc_slot_info *); }; /* @@ -805,6 +806,14 @@ int sc_wait_for_event(sc_reader_t **readers, int *slots, size_t nslots, unsigned int event_mask, int *reader, unsigned int *event, int timeout); +/** + * Resets the card. + * NOTE: only PC/SC backend implements this function at this moment. + * @param card The card to reset. + * @retval SC_SUCCESS on success + */ +int sc_reset(sc_card_t *card); + /** * Locks the card against modification from other threads. * After the initial call to sc_lock, the card is protected from diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index b6494eca..883bb813 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -93,6 +93,7 @@ struct pcsc_slot_data { SCARD_READERSTATE_A reader_state; DWORD verify_ioctl; DWORD modify_ioctl; + int locked; }; static int pcsc_detect_card_presence(sc_reader_t *reader, sc_slot_info_t *slot); @@ -452,7 +453,7 @@ static int pcsc_wait_for_event(sc_reader_t **readers, } } -static int pcsc_reconnect(sc_reader_t * reader, sc_slot_info_t * slot) +static int pcsc_reconnect(sc_reader_t * reader, sc_slot_info_t * slot, int reset) { DWORD active_proto, protocol; LONG rv; @@ -476,9 +477,12 @@ static int pcsc_reconnect(sc_reader_t * reader, sc_slot_info_t * slot) protocol = slot->active_protocol; } + /* reconnect always unlocks transaction */ + pslot->locked = 0; + rv = SCardReconnect(pslot->pcsc_card, priv->gpriv->connect_exclusive ? SCARD_SHARE_EXCLUSIVE : SCARD_SHARE_SHARED, protocol, - SCARD_LEAVE_CARD, &active_proto); + reset ? SCARD_RESET_CARD : SCARD_LEAVE_CARD, &active_proto); if (rv != SCARD_S_SUCCESS) { PCSC_ERROR(reader->ctx, "SCardReconnect failed", rv); return pcsc_ret_to_error(rv); @@ -524,6 +528,9 @@ static int pcsc_connect(sc_reader_t *reader, sc_slot_info_t *slot) slot->active_protocol = pcsc_proto_to_opensc(active_proto); pslot->pcsc_card = card_handle; + /* after connect reader is not locked yet */ + pslot->locked = 0; + /* check for pinpad support */ #ifdef PINPAD_ENABLED sc_debug(reader->ctx, "Requesting reader features ... "); @@ -586,7 +593,7 @@ static int pcsc_lock(sc_reader_t *reader, sc_slot_info_t *slot) if ((unsigned int)rv == SCARD_W_RESET_CARD) { /* try to reconnect if the card was reset by some other application */ - rv = pcsc_reconnect(reader, slot); + rv = pcsc_reconnect(reader, slot, 0); if (rv != SCARD_S_SUCCESS) { PCSC_ERROR(reader->ctx, "SCardReconnect failed", rv); return pcsc_ret_to_error(rv); @@ -600,6 +607,9 @@ static int pcsc_lock(sc_reader_t *reader, sc_slot_info_t *slot) PCSC_ERROR(reader->ctx, "SCardBeginTransaction failed", rv); return pcsc_ret_to_error(rv); } + + pslot->locked = 1; + return SC_SUCCESS; } @@ -610,12 +620,16 @@ static int pcsc_unlock(sc_reader_t *reader, sc_slot_info_t *slot) struct pcsc_private_data *priv = GET_PRIV_DATA(reader); assert(pslot != NULL); + rv = SCardEndTransaction(pslot->pcsc_card, priv->gpriv->transaction_reset ? SCARD_RESET_CARD : SCARD_LEAVE_CARD); if (rv != SCARD_S_SUCCESS) { PCSC_ERROR(reader->ctx, "SCardEndTransaction failed", rv); return pcsc_ret_to_error(rv); } + + pslot->locked = 0; + return 0; } @@ -635,6 +649,23 @@ static int pcsc_release(sc_reader_t *reader) return 0; } +static int pcsc_reset(sc_reader_t *reader, sc_slot_info_t *slot) +{ + int r; + struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); + int old_locked = pslot->locked; + + r = pcsc_reconnect(reader, slot, 1); + if(r != SC_SUCCESS) + return r; + + /* pcsc_reconnect unlocks card... try to lock it again if it was locked */ + if(old_locked) + r = pcsc_lock(reader, slot); + + return r; +} + static struct sc_reader_operations pcsc_ops; static struct sc_reader_driver pcsc_drv = { @@ -784,6 +815,7 @@ struct sc_reader_driver * sc_get_pcsc_driver(void) pcsc_ops.disconnect = pcsc_disconnect; pcsc_ops.perform_verify = pcsc_pin_cmd; pcsc_ops.wait_for_event = pcsc_wait_for_event; + pcsc_ops.reset = pcsc_reset; return &pcsc_drv; }