Hello All,

CC you as I changed the subject, to meet the discussion.

On 12/19/08, Peter Stuge <pe...@stuge.se> 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
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to