Hello All,
CC you as I changed the subject, to meet the discussion.
On 12/19/08, Peter Stuge <[email protected]> wrote:
> USB is completely driven by the host, so unless an app keeps a
> transfer pending for the interrupt pipe, nothing will be transfered.
> The USB function (reader) detects that it couldn't send and takes
> some action, typically either throwing the message away, or queueing
> it for a retry later.
Well... I must say I do not understand the low level implementation of
USB... I wrote a sample program you can play with, and see that it
actually work.
I tried to keep as much code as I could from OpenCT.
At least with the SCR335 sample I have it detects card removal and
card insert with no CPU footprint. It also handles termination signal
and reader detach.
I will be happy to know if I did something wrong.
Thanks.
Alon.
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#include <linux/usbdevice_fs.h>
#define IFD_ERROR_NO_MEMORY -10
#define IFD_ERROR_COMM_ERROR -5
#define IFD_ERROR_TIMEOUT -2
typedef struct ifd_device ifd_device_t;
struct ifd_device {
int fd;
};
enum {
IFD_USB_URB_TYPE_ISO = 0,
IFD_USB_URB_TYPE_INTERRUPT = 1,
IFD_USB_URB_TYPE_CONTROL = 2,
IFD_USB_URB_TYPE_BULK = 3
};
typedef struct ifd_usb_capture ifd_usb_capture_t;
#define ifd_time_elapsed(x) 0
#define ifd_usb_begin_capture ifd_sysdep_usb_begin_capture
#define ifd_usb_capture_once ifd_sysdep_usb_capture_once
#define ifd_usb_end_capture ifd_sysdep_usb_end_capture
void ifd_debug(int n, char *format, ...) {
va_list args;
(void)n;
va_start(args, format);
vprintf(format, args);
printf("\n");
va_end(args);
}
void ct_error(char *format, ...) {
va_list args;
va_start(args, format);
vprintf(format, args);
printf("\n");
va_end(args);
}
/*
* USB URB capture
*/
struct ifd_usb_capture {
struct usbdevfs_urb urb;
int type;
int endpoint;
size_t maxpacket;
};
static int usb_submit_urb(int fd, struct ifd_usb_capture *cap)
{
/* Fill in the URB details */
ifd_debug(6, "submit urb %p", &cap->urb);
memset(&cap->urb, 0, sizeof(cap->urb));
cap->urb.type = cap->type;
cap->urb.endpoint = cap->endpoint;
cap->urb.buffer = (caddr_t) (cap + 1);
cap->urb.buffer_length = cap->maxpacket;
return ioctl(fd, USBDEVFS_SUBMITURB, &cap->urb);
}
int ifd_sysdep_usb_end_capture(ifd_device_t * dev, ifd_usb_capture_t * cap)
{
int rc = 0;
if (ioctl(dev->fd, USBDEVFS_DISCARDURB, &cap->urb) < 0
&& errno != EINVAL) {
ct_error("usb_discardurb failed: %m");
rc = IFD_ERROR_COMM_ERROR;
}
/* Discarding an URB will place it in the queue of completed
* request, with urb->status == -1. So if we don't reap this
* URB now, the next call to REAPURB will return this one,
* clobbering random memory.
*/
(void)ioctl(dev->fd, USBDEVFS_REAPURBNDELAY, &cap->urb);
free(cap);
return rc;
}
int ifd_sysdep_usb_begin_capture(ifd_device_t * dev, int type, int endpoint,
size_t maxpacket, ifd_usb_capture_t ** capret)
{
ifd_usb_capture_t *cap;
cap = (ifd_usb_capture_t *) calloc(1, sizeof(*cap) + maxpacket);
if (!cap) {
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
cap->type = type;
cap->endpoint = endpoint;
cap->maxpacket = maxpacket;
if (usb_submit_urb(dev->fd, cap) < 0) {
ct_error("usb_submiturb failed: %m");
ifd_sysdep_usb_end_capture(dev, cap);
return IFD_ERROR_COMM_ERROR;
}
*capret = cap;
return 0;
}
int ifd_sysdep_usb_capture_once(ifd_device_t * dev, ifd_usb_capture_t * cap,
void *buffer, size_t len)
{
struct usbdevfs_urb *purb;
size_t copied = 0;
int rc = 0;
purb = NULL;
rc = ioctl(dev->fd, USBDEVFS_REAPURBNDELAY, &purb);
if (rc < 0) {
if (errno == EAGAIN)
return 0;
ct_error("usb_reapurb failed: %m");
return IFD_ERROR_COMM_ERROR;
}
if (purb != &cap->urb) {
ifd_debug(2, "reaped usb urb %p", purb);
return 0;
}
if (purb->actual_length) {
ifd_debug(6, "usb reapurb: len=%u",
purb->actual_length);
if ((copied = purb->actual_length) > len)
copied = len;
if (copied && buffer)
memcpy(buffer, purb->buffer, copied);
}
else {
usleep(10000);
}
/* Re-submit URB */
usb_submit_urb(dev->fd, cap);
return copied;
}
int ifd_sysdep_usb_open(const char *device)
{
return open(device, O_RDWR);
}
static int ccid_card_status(ifd_device_t * dev, ifd_usb_capture_t *cap, int *slotstatus, int numslots)
{
unsigned char ret[20];
int r;
r = ifd_usb_capture_once(dev, cap, ret, 8);
if (r > 0) {
if (ret[0] == 0x50) {
int i;
{
int i;
printf("status received: ");
for (i=0;i<r;i++) {
printf ("%02x ", ret[i]);
}
printf("\n");
}
for (i=0;i<numslots;i++) {
if (1 + (i / 4) < r) {
int bits = (ret[1 + (i / 4)] >> (2 * (i % 4))) & 0x3;
#if 0
if (bits & 2)
/* changed */;
#endif
if (bits & 1)
slotstatus[i] = 1;
else
slotstatus[i] = 0;
}
}
r = 1;
}
else {
r = 0;
}
}
return r;
}
static int should_quit = 0;
void sigterm(int n) {
(void)n;
should_quit = 1;
ifd_debug(3, "SIGNAL");
}
int main(int argc, char *argv[]) {
struct sigaction act;
ifd_device_t ifd_device;
ifd_usb_capture_t *cap;
int r;
char *device;
int ep_intr;
#define POLL_TIMEOUT 10000
#define MAX_SLOTS 8
int slots[MAX_SLOTS];
if (argc != 3) {
printf("Usage: device ep_intr\n");
exit(1);
}
device = argv[1];
ep_intr = atoi(argv[2]);
memset(slots, 0xff, sizeof(slots));
memset(&act, 0, sizeof(act));
act.sa_handler = sigterm;
sigaction(SIGTERM, &act, NULL);
sigaction(SIGINT, &act, NULL);
memset(&ifd_device, 0, sizeof(ifd_device));
ifd_debug(3, "Opening device %s", device);
ifd_device.fd = ifd_sysdep_usb_open(device);
ifd_debug(3, "ifd_usb_begin_capture");
if (
ifd_usb_begin_capture(
&ifd_device,
IFD_USB_URB_TYPE_INTERRUPT,
ep_intr,
8,
&cap
) < 0
) {
ct_error("ccid: begin capture: %d", r);
exit(1);
}
while (!should_quit) {
struct pollfd pfd;
int r;
pfd.fd = ifd_device.fd;
pfd.events = POLLOUT | POLLERR;
ifd_debug(3, "Before poll");
r = poll(&pfd, 1, POLL_TIMEOUT);
if (r < 0) {
ifd_debug(3, "Wakeup on error");
if (errno == EAGAIN || errno == EINTR) {
ifd_debug(3, "ignoring error");
}
else {
ifd_debug(3, "Error, quiting");
break;
}
}
else if (r == 0) {
ifd_debug(3, "Wakeup on timeout");
}
else {
ifd_debug(3, "Wakeup on pending io");
if (pfd.revents == POLLERR) {
ifd_debug(3, "no reader");
break;
}
r = ccid_card_status(&ifd_device, cap, slots, MAX_SLOTS);
if (r < 0) {
ifd_debug(3, "no reader");
break;
}
else if (r == 0) {
ifd_debug(3, "Incomplete response");
}
else {
int i;
printf("EVENT: ");
for (i=0;i<MAX_SLOTS;i++) {
printf("slot%d=%d ", i, slots[i]);
}
printf("\n");
}
}
}
ifd_debug(3, "Cleanup");
ifd_usb_end_capture(&ifd_device, cap);
close(ifd_device.fd);
exit(0);
return 0;
}
_______________________________________________
opensc-devel mailing list
[email protected]
http://www.opensc-project.org/mailman/listinfo/opensc-devel