[PC/SC] detect other events besides card insertion/removal

* remove whitespace.
 * don't use SC_MAX_READERS and allocate memory dynamically.


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3987 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
martin 2010-02-03 09:54:02 +00:00
parent 4c34f5b28c
commit 36992b4001
1 changed files with 92 additions and 69 deletions

View File

@ -2,6 +2,7 @@
* reader-pcsc.c: Reader driver for PC/SC interface
*
* Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi>
* Copyright (C) 2009,2010 Martin Paljak <martin@paljak.pri.ee>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -683,6 +684,8 @@ static int pcsc_finish(sc_context_t *ctx, void *prv_data)
{
struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) prv_data;
SC_FUNC_CALLED(ctx, 3);
if (gpriv) {
if (gpriv->pcsc_ctx != -1)
gpriv->SCardReleaseContext(gpriv->pcsc_ctx);
@ -950,30 +953,20 @@ static int pcsc_wait_for_event(sc_context_t *ctx,
{
struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *)reader_data;
LONG rv;
SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS + 1];
unsigned long on_bits, off_bits;
SCARD_READERSTATE_A *rgReaderStates;
size_t i;
unsigned int num_watch;
int r = SC_ERROR_INTERNAL;
SC_FUNC_CALLED(ctx, 3);
on_bits = off_bits = 0;
if (event_mask & SC_EVENT_CARD_INSERTED) {
event_mask &= ~SC_EVENT_CARD_INSERTED;
on_bits |= SCARD_STATE_PRESENT;
}
if (event_mask & SC_EVENT_CARD_REMOVED) {
event_mask &= ~SC_EVENT_CARD_REMOVED;
off_bits |= SCARD_STATE_PRESENT;
}
/* FIXME check for unhandled masks?
if (event_mask != 0)
return SC_ERROR_INVALID_ARGUMENTS; */
rgReaderStates = (SCARD_READERSTATE_A *) calloc(sc_ctx_get_reader_count(ctx) + 1, sizeof(SCARD_READERSTATE_A));
if (!rgReaderStates)
return SC_ERROR_OUT_OF_MEMORY;
/* Find out the current status */
num_watch = sc_ctx_get_reader_count(ctx);
sc_debug(ctx, "Watching %d readers\n", num_watch);
sc_debug(ctx, "Trying to watch %d readers", num_watch);
for (i = 0; i < num_watch; i++) {
rgReaderStates[i].szReader = sc_ctx_get_reader(ctx, i)->name;
rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
@ -993,7 +986,8 @@ static int pcsc_wait_for_event(sc_context_t *ctx,
rv = gpriv->SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &gpriv->pcsc_wait_ctx);
if (rv != SCARD_S_SUCCESS) {
PCSC_LOG(ctx, "SCardEstablishContext(wait) failed", rv);
return pcsc_to_opensc_error(rv);
r = pcsc_to_opensc_error(rv);
goto out;
}
}
#else
@ -1002,14 +996,16 @@ static int pcsc_wait_for_event(sc_context_t *ctx,
if (num_watch == 0) {
sc_debug(ctx, "No readers available, PnP notification not supported");
*event_reader = NULL;
return SC_ERROR_NO_READERS_FOUND;
r = SC_ERROR_NO_READERS_FOUND;
goto out;
}
rv = gpriv->SCardGetStatusChange(gpriv->pcsc_wait_ctx, 0, rgReaderStates, num_watch);
if (rv != SCARD_S_SUCCESS) {
if (rv != (LONG)SCARD_E_TIMEOUT) {
PCSC_LOG(ctx, "SCardGetStatusChange(1) failed", rv);
return pcsc_to_opensc_error(rv);
r = pcsc_to_opensc_error(rv);
goto out;
}
}
@ -1027,26 +1023,43 @@ static int pcsc_wait_for_event(sc_context_t *ctx,
sc_debug(ctx, "%s before=0x%04X now=0x%04X", rsp->szReader, rsp->dwCurrentState, rsp->dwEventState);
prev_state = rsp->dwCurrentState;
state = rsp->dwEventState;
if ((state & on_bits & SCARD_STATE_PRESENT) &&
(prev_state & SCARD_STATE_EMPTY))
if (state & SCARD_STATE_CHANGED) {
/* check for hotplug events */
if (!strcmp(rgReaderStates[i].szReader, "\\\\?PnP?\\Notification")) {
sc_debug(ctx, "detected hotplug event");
*event |= SC_EVENT_READER_ATTACHED;
*event_reader = NULL;
}
if ((state & SCARD_STATE_PRESENT) && !(prev_state & SCARD_STATE_PRESENT)) {
sc_debug(ctx, "card inserted event");
*event |= SC_EVENT_CARD_INSERTED;
if ((~state & off_bits & SCARD_STATE_PRESENT) &&
(prev_state & SCARD_STATE_PRESENT))
}
if ((prev_state & SCARD_STATE_PRESENT) && !(state & SCARD_STATE_PRESENT)) {
sc_debug(ctx, "card removed event");
*event |= SC_EVENT_CARD_REMOVED;
if (*event) {
sc_debug(ctx, "Event 0x%02X in reader %s", *event, rsp->szReader);
}
if ((state & SCARD_STATE_UNKNOWN) && !(prev_state & SCARD_STATE_UNKNOWN)) {
sc_debug(ctx, "reader detached event");
*event |= SC_EVENT_READER_DETACHED;
}
if ((prev_state & SCARD_STATE_UNKNOWN) && !(state & SCARD_STATE_UNKNOWN)) {
sc_debug(ctx, "reader re-attached event");
*event |= SC_EVENT_READER_ATTACHED;
}
if (*event & event_mask) {
sc_debug(ctx, "Matching event 0x%02X in reader %s", *event, rsp->szReader);
*event_reader = sc_ctx_get_reader_by_name(ctx, rsp->szReader);
r = SC_SUCCESS;
goto out;
SC_FUNC_RETURN(ctx, 3, SC_SUCCESS);
}
/* check for hotplug event */
if (strcmp(rgReaderStates[i].szReader, "\\\\?PnP?\\Notification") == 0 && event_mask & SC_EVENT_READER_ATTACHED) {
if (state & SCARD_STATE_CHANGED) {
sc_debug(ctx, "detected hotplug event");
*event = SC_EVENT_READER_ATTACHED;
*event_reader = NULL;
SC_FUNC_RETURN(ctx, 3, SC_SUCCESS);
}
}
/* No match - copy the state so pcscd knows
@ -1054,29 +1067,39 @@ static int pcsc_wait_for_event(sc_context_t *ctx,
rsp->dwCurrentState = rsp->dwEventState;
}
/* Set the timeout if caller wants to time out */
if (timeout == 0)
return SC_ERROR_EVENT_TIMEOUT;
if (timeout == 0) {
r = SC_ERROR_EVENT_TIMEOUT;
goto out;
}
/* Set the timeout if caller wants to time out */
if (timeout == -1) {
timeout = INFINITE;
}
sc_debug(ctx, "Sleeping call, timeout 0x%lx", timeout);
rv = gpriv->SCardGetStatusChange(gpriv->pcsc_wait_ctx, timeout, rgReaderStates, num_watch);
if (rv == (LONG) SCARD_E_CANCELLED) {
/* C_Finalize was called, events don't matter */
return SC_ERROR_EVENT_TIMEOUT;
r = SC_ERROR_EVENT_TIMEOUT;
goto out;
}
if (rv == (LONG) SCARD_E_TIMEOUT) {
return SC_ERROR_EVENT_TIMEOUT;
r = SC_ERROR_EVENT_TIMEOUT;
goto out;
}
if (rv != SCARD_S_SUCCESS) {
PCSC_LOG(ctx, "SCardGetStatusChange(2) failed", rv);
return pcsc_to_opensc_error(rv);
r = pcsc_to_opensc_error(rv);
goto out;
}
}
out:
free(rgReaderStates);
SC_FUNC_RETURN(ctx, 3, r);
}