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