- restructured handling of interrupt thread to kill the thread along with all
the others - fixed error on input parameter parsing when interrupt is activated - completed interrupt signaling for new/removed cards git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@166 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
@@ -146,7 +146,7 @@ int ccid_initialize(int reader_id, const char *cdriver, int verbose)
|
|||||||
return SC_SUCCESS;
|
return SC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ccid_shutdown(void)
|
void ccid_shutdown()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < sizeof *card_in_slot; i++) {
|
for (i = 0; i < sizeof *card_in_slot; i++) {
|
||||||
@@ -1050,11 +1050,14 @@ err:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX calling sc_wait_for_event blocks all other threads, thats why it
|
||||||
|
* can't be used here... */
|
||||||
static int
|
static int
|
||||||
get_RDR_to_PC_NotifySlotChange(RDR_to_PC_NotifySlotChange_t **out)
|
get_RDR_to_PC_NotifySlotChange(RDR_to_PC_NotifySlotChange_t **out)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int sc_result;
|
int sc_result;
|
||||||
|
uint8_t oldmask;
|
||||||
uint8_t changed [] = {
|
uint8_t changed [] = {
|
||||||
CCID_SLOT1_CHANGED,
|
CCID_SLOT1_CHANGED,
|
||||||
CCID_SLOT2_CHANGED,
|
CCID_SLOT2_CHANGED,
|
||||||
@@ -1078,19 +1081,46 @@ get_RDR_to_PC_NotifySlotChange(RDR_to_PC_NotifySlotChange_t **out)
|
|||||||
|
|
||||||
result->bMessageType = 0x50;
|
result->bMessageType = 0x50;
|
||||||
result->bmSlotICCState = CCID_SLOTS_UNCHANGED;
|
result->bmSlotICCState = CCID_SLOTS_UNCHANGED;
|
||||||
|
oldmask = CCID_SLOTS_UNCHANGED;
|
||||||
|
|
||||||
for (i = 0; i < reader->slot_count; i++) {
|
for (i = 0; i < reader->slot_count; i++) {
|
||||||
sc_result = detect_card_presence(i);
|
sc_result = detect_card_presence(i);
|
||||||
if (sc_result < 0) {
|
if (sc_result < 0) {
|
||||||
debug_sc_result(sc_result);
|
|
||||||
sc_error(ctx, "Could not detect card presence, skipping slot %d.",
|
sc_error(ctx, "Could not detect card presence, skipping slot %d.",
|
||||||
i);
|
i);
|
||||||
|
debug_sc_result(sc_result);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc_result & SC_SLOT_CARD_PRESENT)
|
||||||
|
oldmask |= present[i];
|
||||||
|
if (sc_result & SC_SLOT_CARD_CHANGED) {
|
||||||
|
sc_debug(ctx, "Card status changed in slot %d.", i);
|
||||||
|
result->bmSlotICCState |= changed[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(10);
|
||||||
|
|
||||||
|
for (i = 0; i < reader->slot_count; i++) {
|
||||||
|
sc_result = detect_card_presence(i);
|
||||||
|
if (sc_result < 0) {
|
||||||
|
sc_error(ctx, "Could not detect card presence, skipping slot %d.",
|
||||||
|
i);
|
||||||
|
debug_sc_result(sc_result);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc_result & SC_SLOT_CARD_PRESENT)
|
if (sc_result & SC_SLOT_CARD_PRESENT)
|
||||||
result->bmSlotICCState |= present[i];
|
result->bmSlotICCState |= present[i];
|
||||||
if (sc_result & SC_SLOT_CARD_CHANGED) {
|
if (sc_result & SC_SLOT_CARD_CHANGED) {
|
||||||
|
sc_debug(ctx, "Card status changed in slot %d.", i);
|
||||||
|
result->bmSlotICCState |= changed[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((oldmask & present[i]) != (result->bmSlotICCState & present[i])) {
|
||||||
|
sc_debug(ctx, "Card status changed in slot %d.", i);
|
||||||
result->bmSlotICCState |= changed[i];
|
result->bmSlotICCState |= changed[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ struct hid_class_descriptor {
|
|||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
int ccid_initialize(int reader_id, const char *cdriver, int verbose);
|
int ccid_initialize(int reader_id, const char *cdriver, int verbose);
|
||||||
void ccid_shutdown(void);
|
void ccid_shutdown();
|
||||||
|
|
||||||
int ccid_parse_bulkin(const __u8* inbuf, size_t inlen, __u8** outbuf);
|
int ccid_parse_bulkin(const __u8* inbuf, size_t inlen, __u8** outbuf);
|
||||||
int ccid_parse_control(struct usb_ctrlrequest *setup, __u8 **outbuf);
|
int ccid_parse_control(struct usb_ctrlrequest *setup, __u8 **outbuf);
|
||||||
|
|||||||
148
ccid/src/usb.c
148
ccid/src/usb.c
@@ -78,7 +78,7 @@ static const struct option options[] = {
|
|||||||
{ "serial", required_argument, NULL, OPT_SERIAL },
|
{ "serial", required_argument, NULL, OPT_SERIAL },
|
||||||
{ "product", required_argument, NULL, OPT_PRODUCT },
|
{ "product", required_argument, NULL, OPT_PRODUCT },
|
||||||
{ "vendor", required_argument, NULL, OPT_VENDOR },
|
{ "vendor", required_argument, NULL, OPT_VENDOR },
|
||||||
{ "interrupt", no_argument, &doint, OPT_INTERRUPT },
|
{ "interrupt", no_argument, NULL, OPT_INTERRUPT },
|
||||||
{ "verbose", no_argument, NULL, OPT_VERBOSE },
|
{ "verbose", no_argument, NULL, OPT_VERBOSE },
|
||||||
{ "info", no_argument, NULL, OPT_INFO },
|
{ "info", no_argument, NULL, OPT_INFO },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
@@ -846,6 +846,7 @@ static pthread_t ep0;
|
|||||||
|
|
||||||
static pthread_t ccid_thread;
|
static pthread_t ccid_thread;
|
||||||
static pthread_t hidthread;
|
static pthread_t hidthread;
|
||||||
|
static pthread_t interrupt_thread;
|
||||||
static int source_fd = -1;
|
static int source_fd = -1;
|
||||||
static int sink_fd = -1;
|
static int sink_fd = -1;
|
||||||
static int status_fd = -1;
|
static int status_fd = -1;
|
||||||
@@ -938,65 +939,51 @@ ep_config (char *name, const char *label,
|
|||||||
#define hidstatus_open(name) \
|
#define hidstatus_open(name) \
|
||||||
ep_config(name,__FUNCTION__, &fs_hid_status_desc, &hs_hid_status_desc)
|
ep_config(name,__FUNCTION__, &fs_hid_status_desc, &hs_hid_status_desc)
|
||||||
|
|
||||||
|
static void *interrupt (void *param)
|
||||||
|
{
|
||||||
|
status_fd = status_open (((char **) param)[0]);
|
||||||
|
if (source_fd < 0) {
|
||||||
|
/* an error concerning status endpoint is not fatal for in/out bulk*/
|
||||||
|
/* transfer */
|
||||||
|
if (verbose > 1)
|
||||||
|
perror("status_fd");
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
pthread_cleanup_push (close_fd, &status_fd);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
RDR_to_PC_NotifySlotChange_t *slotchange;
|
||||||
|
do {
|
||||||
|
/* original LinuxThreads cancelation didn't work right */
|
||||||
|
/* so test for it explicitly. */
|
||||||
|
pthread_testcancel ();
|
||||||
|
|
||||||
|
if (ccid_state_changed(&slotchange, -1)) {
|
||||||
|
/* don't bother host, when nothing changed */
|
||||||
|
if (verbose > 1)
|
||||||
|
fprintf(stderr, "interrupt loop: writing RDR_to_PC_NotifySlotChange... ");
|
||||||
|
result = write(status_fd, slotchange, sizeof *slotchange);
|
||||||
|
if (verbose > 1)
|
||||||
|
fprintf(stderr, "done.\n");
|
||||||
|
}
|
||||||
|
} while (result >= 0);
|
||||||
|
|
||||||
|
if (errno != ESHUTDOWN || result < 0) {
|
||||||
|
perror ("interrupt loop aborted");
|
||||||
|
pthread_cancel(ep0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_cleanup_pop (1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ccid thread, forwards ccid requests to pcsc and returns results */
|
/* ccid thread, forwards ccid requests to pcsc and returns results */
|
||||||
static void *ccid (void *param)
|
static void *ccid (void *param)
|
||||||
{
|
{
|
||||||
pthread_t interrupt_thread;
|
|
||||||
|
|
||||||
void *interrupt (void *param)
|
|
||||||
{
|
|
||||||
status_fd = status_open (((char **) param)[0]);
|
|
||||||
if (source_fd < 0) {
|
|
||||||
/* an error concerning status endpoint is not fatal for in/out bulk*/
|
|
||||||
/* transfer */
|
|
||||||
if (verbose > 1)
|
|
||||||
perror("status_fd");
|
|
||||||
pthread_exit(0);
|
|
||||||
}
|
|
||||||
pthread_cleanup_push (close_fd, &status_fd);
|
|
||||||
|
|
||||||
int result;
|
|
||||||
RDR_to_PC_NotifySlotChange_t *slotchange;
|
|
||||||
do {
|
|
||||||
/* original LinuxThreads cancelation didn't work right */
|
|
||||||
/* so test for it explicitly. */
|
|
||||||
pthread_testcancel ();
|
|
||||||
|
|
||||||
if (ccid_state_changed(&slotchange, -1)) {
|
|
||||||
/* don't bother host, when nothing changed */
|
|
||||||
if (verbose > 1)
|
|
||||||
fprintf(stderr, "interrupt loop: writing RDR_to_PC_NotifySlotChange... ");
|
|
||||||
result = write(status_fd, slotchange, sizeof *slotchange);
|
|
||||||
if (verbose > 1)
|
|
||||||
fprintf(stderr, "done.\n");
|
|
||||||
}
|
|
||||||
} while (result >= 0);
|
|
||||||
|
|
||||||
if (errno != ESHUTDOWN || result < 0) {
|
|
||||||
perror ("interrupt loop aborted");
|
|
||||||
pthread_cancel(ccid_thread);
|
|
||||||
pthread_cancel(ep0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_cleanup_pop (1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close_interrupt ()
|
|
||||||
{
|
|
||||||
if (doint) {
|
|
||||||
pthread_cancel(interrupt_thread);
|
|
||||||
if (pthread_join (interrupt_thread, 0) != 0)
|
|
||||||
perror ("can't join interrupt thread");
|
|
||||||
fprintf (stderr, "cancled interrupt loop\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char **names = (char **) param;
|
char **names = (char **) param;
|
||||||
char *source_name = names[0];
|
char *source_name = names[0];
|
||||||
char *sink_name = names[1];
|
char *sink_name = names[1];
|
||||||
char *status_name = names[2];
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
source_fd = source_open (source_name);
|
source_fd = source_open (source_name);
|
||||||
@@ -1013,23 +1000,10 @@ static void *ccid (void *param)
|
|||||||
perror("sink_fd");
|
perror("sink_fd");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
pthread_cleanup_push (close_fd, &sink_fd);
|
pthread_cleanup_push (close_fd, &sink_fd);
|
||||||
|
|
||||||
pthread_cleanup_push (ccid_shutdown, NULL);
|
pthread_cleanup_push (ccid_shutdown, NULL);
|
||||||
|
|
||||||
if (doint) {
|
|
||||||
static char * interruptnames[1];
|
|
||||||
interruptnames[0] = status_name;
|
|
||||||
if (pthread_create (&interrupt_thread, NULL, interrupt, (void *)
|
|
||||||
interruptnames) != 0) {
|
|
||||||
perror ("can't create interrupt thread");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
} else if (verbose) {
|
|
||||||
fprintf (stderr, "interrupt pipe disabled\n");
|
|
||||||
}
|
|
||||||
pthread_cleanup_push (close_interrupt, NULL);
|
|
||||||
|
|
||||||
__u8 *outbuf = NULL;
|
__u8 *outbuf = NULL;
|
||||||
pthread_cleanup_push (free, outbuf);
|
pthread_cleanup_push (free, outbuf);
|
||||||
size_t bufsize = 512;
|
size_t bufsize = 512;
|
||||||
@@ -1049,18 +1023,18 @@ static void *ccid (void *param)
|
|||||||
pthread_testcancel ();
|
pthread_testcancel ();
|
||||||
|
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
fprintf(stderr, "reading %lu bytes... ", (long unsigned) bufsize);
|
fprintf(stderr, "bulk loop: reading %lu bytes... ", (long unsigned) bufsize);
|
||||||
result = read(sink_fd, inbuf, bufsize);
|
result = read(sink_fd, inbuf, bufsize);
|
||||||
if (result < 0) break;
|
if (result < 0) break;
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
fprintf(stderr, "got %d, done.\n", result);
|
fprintf(stderr, "bulk loop: got %d, done.\n", result);
|
||||||
if (!result) break;
|
if (!result) break;
|
||||||
|
|
||||||
result = ccid_parse_bulkin(inbuf, result, &outbuf);
|
result = ccid_parse_bulkin(inbuf, result, &outbuf);
|
||||||
if (result < 0) break;
|
if (result < 0) break;
|
||||||
|
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
fprintf(stderr, "writing %d bytes... ", result);
|
fprintf(stderr, "bulk loop: writing %d bytes... ", result);
|
||||||
result = write(source_fd, outbuf, result);
|
result = write(source_fd, outbuf, result);
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
fprintf(stderr, "done.\n");
|
fprintf(stderr, "done.\n");
|
||||||
@@ -1076,7 +1050,6 @@ static void *ccid (void *param)
|
|||||||
pthread_cleanup_pop (1);
|
pthread_cleanup_pop (1);
|
||||||
pthread_cleanup_pop (1);
|
pthread_cleanup_pop (1);
|
||||||
pthread_cleanup_pop (1);
|
pthread_cleanup_pop (1);
|
||||||
pthread_cleanup_pop (1);
|
|
||||||
|
|
||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
fflush (stderr);
|
fflush (stderr);
|
||||||
@@ -1086,7 +1059,6 @@ static void *ccid (void *param)
|
|||||||
error:
|
error:
|
||||||
pthread_cancel(ep0);
|
pthread_cancel(ep0);
|
||||||
pthread_exit(0);
|
pthread_exit(0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *hid (void *param)
|
static void *hid (void *param)
|
||||||
@@ -1185,7 +1157,6 @@ static void start_io (void)
|
|||||||
static char *names[2];
|
static char *names[2];
|
||||||
names[0] = EP_IN_NAME;
|
names[0] = EP_IN_NAME;
|
||||||
names[1] = EP_OUT_NAME;
|
names[1] = EP_OUT_NAME;
|
||||||
names[2] = EP_STATUS_NAME;
|
|
||||||
if (pthread_create (&ccid_thread, NULL, ccid, (void *) names) != 0) {
|
if (pthread_create (&ccid_thread, NULL, ccid, (void *) names) != 0) {
|
||||||
perror ("can't create ccid thread");
|
perror ("can't create ccid thread");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@@ -1203,6 +1174,17 @@ static void start_io (void)
|
|||||||
if (verbose)
|
if (verbose)
|
||||||
fprintf (stderr, "HID disabled.\n");
|
fprintf (stderr, "HID disabled.\n");
|
||||||
}
|
}
|
||||||
|
if (doint) {
|
||||||
|
static char * interruptnames[1];
|
||||||
|
interruptnames[0] = EP_STATUS_NAME;
|
||||||
|
if (pthread_create (&interrupt_thread, NULL, interrupt, (void *)
|
||||||
|
interruptnames) != 0) {
|
||||||
|
perror ("can't create interrupt thread");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else if (verbose) {
|
||||||
|
fprintf (stderr, "interrupt pipe disabled\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* give the other threads a chance to run before we report
|
/* give the other threads a chance to run before we report
|
||||||
* success to the host.
|
* success to the host.
|
||||||
@@ -1228,13 +1210,20 @@ static void stop_io ()
|
|||||||
ccid_thread = ep0;
|
ccid_thread = ep0;
|
||||||
fprintf (stderr, "cancled ccid\n");
|
fprintf (stderr, "cancled ccid\n");
|
||||||
}
|
}
|
||||||
if (!pthread_equal (ccid_thread, ep0)) {
|
if (!pthread_equal (hidthread, ep0)) {
|
||||||
pthread_cancel (hidthread);
|
pthread_cancel (hidthread);
|
||||||
if (pthread_join (hidthread, 0) != 0)
|
if (pthread_join (hidthread, 0) != 0)
|
||||||
perror ("can't join hid thread");
|
perror ("can't join hid thread");
|
||||||
hidthread = ep0;
|
hidthread = ep0;
|
||||||
fprintf (stderr, "cancled hid\n");
|
fprintf (stderr, "cancled hid\n");
|
||||||
}
|
}
|
||||||
|
if (!pthread_equal (interrupt_thread, ep0)) {
|
||||||
|
pthread_cancel (interrupt_thread);
|
||||||
|
if (pthread_join (interrupt_thread, 0) != 0)
|
||||||
|
perror ("can't join interrupt thread");
|
||||||
|
interrupt_thread = ep0;
|
||||||
|
fprintf (stderr, "cancled interrupt\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@@ -1507,7 +1496,7 @@ special:
|
|||||||
if (result < 0 || result > 256)
|
if (result < 0 || result > 256)
|
||||||
goto stall;
|
goto stall;
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
fprintf(stderr, "writing %d bytes... ", result);
|
fprintf(stderr, "control loop: writing %d bytes... ", result);
|
||||||
result = write (fd, outbuf, result);
|
result = write (fd, outbuf, result);
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
fprintf(stderr, "done.\n");
|
fprintf(stderr, "done.\n");
|
||||||
@@ -1573,9 +1562,9 @@ static void *ep0_thread (void *param)
|
|||||||
time_t now, last;
|
time_t now, last;
|
||||||
struct pollfd ep0_poll;
|
struct pollfd ep0_poll;
|
||||||
|
|
||||||
ccid_thread = ep0 = pthread_self ();
|
interrupt_thread = ccid_thread = hidthread = ep0 = pthread_self ();
|
||||||
pthread_cleanup_push (close_fd, param);
|
|
||||||
pthread_cleanup_push (stop_io, NULL);
|
pthread_cleanup_push (stop_io, NULL);
|
||||||
|
pthread_cleanup_push (close_fd, param);
|
||||||
|
|
||||||
/* REVISIT signal handling ... normally one pthread should
|
/* REVISIT signal handling ... normally one pthread should
|
||||||
* be doing sigwait() to handle all async signals.
|
* be doing sigwait() to handle all async signals.
|
||||||
@@ -1750,6 +1739,9 @@ main (int argc, char **argv)
|
|||||||
case OPT_INFO:
|
case OPT_INFO:
|
||||||
doinfo++;
|
doinfo++;
|
||||||
break;
|
break;
|
||||||
|
case OPT_INTERRUPT:
|
||||||
|
doint++;
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
/* fall through */
|
/* fall through */
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user