/* parse.c: parse CCID structure Copyright (C) 2003-2004 Ludovic Rousseau 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * $Id: parse.c 2679 2007-11-01 17:16:43Z rousseau $ */ #include #include # ifdef S_SPLINT_S # include # endif #include #include #include "defs.h" #include "ccid.h" #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif static int ccid_parse_interface_descriptor(usb_dev_handle *handle, struct usb_device *dev); /***************************************************************************** * * main * ****************************************************************************/ int main(void) { static struct usb_bus *busses = NULL; struct usb_bus *bus; struct usb_dev_handle *dev_handle; int nb = 0; usb_init(); usb_find_busses(); usb_find_devices(); busses = usb_get_busses(); if (busses == NULL) { printf("No USB buses found\n"); return -1; } /* on any USB buses */ for (bus = busses; bus; bus = bus->next) { struct usb_device *dev; /* any device on this bus */ for (dev = bus->devices; dev; dev = dev->next) { struct usb_interface *usb_interface = NULL; int interface; /* check if the device has bInterfaceClass == 11 */ usb_interface = get_ccid_usb_interface(dev); if (NULL == usb_interface) continue; fprintf(stderr, "Trying to open USB bus/device: %s/%s\n", bus->dirname, dev->filename); dev_handle = usb_open(dev); if (NULL == dev_handle) { fprintf(stderr, "Can't usb_open(%s/%s): %s\n", bus->dirname, dev->filename, strerror(errno)); continue; } /* now we found a free reader and we try to use it */ if (NULL == dev->config) { usb_close(dev_handle); fprintf(stderr, "No dev->config found for %s/%s\n", bus->dirname, dev->filename); continue; } usb_interface = get_ccid_usb_interface(dev); if (NULL == usb_interface) { usb_close(dev_handle); fprintf(stderr, "Can't find a CCID interface on %s/%s\n", bus->dirname, dev->filename); continue; } interface = usb_interface->altsetting->bInterfaceNumber; #ifndef __APPLE__ if (usb_claim_interface(dev_handle, interface) < 0) { usb_close(dev_handle); fprintf(stderr, "Can't claim interface %s/%s: %s\n", bus->dirname, dev->filename, strerror(errno)); if (EBUSY == errno) { printf(" \33[01;31mPlease, stop pcscd and retry\33[0m\n\n"); return TRUE; } continue; } #endif ccid_parse_interface_descriptor(dev_handle, dev); #ifndef __APPLE__ usb_release_interface(dev_handle, interface); #endif usb_close(dev_handle); nb++; } } if ((0 == nb) && (0 != geteuid())) fprintf(stderr, "Can't find any CCID device.\nMaybe you must run parse as root?\n"); return 0; } /* main */ /***************************************************************************** * * Parse a CCID USB Descriptor * ****************************************************************************/ static int ccid_parse_interface_descriptor(usb_dev_handle *handle, struct usb_device *dev) { struct usb_interface_descriptor *usb_interface; unsigned char *extra; unsigned char buffer[256*sizeof(int)]; /* maximum is 256 records */ /* * Vendor/model name */ printf(" idVendor: 0x%04X\n", dev->descriptor.idVendor); if (usb_get_string_simple(handle, dev->descriptor.iManufacturer, buffer, sizeof(buffer)) < 0) { printf(" Can't get iManufacturer string\n"); if (getuid()) { printf("\33[01;31mPlease, restart the command as root\33[0m\n\n"); return TRUE; } } else printf(" iManufacturer: %s\n", buffer); printf(" idProduct: 0x%04X\n", dev->descriptor.idProduct); if (usb_get_string_simple(handle, dev->descriptor.iProduct, buffer, sizeof(buffer)) < 0) printf(" Can't get iProduct string\n"); else printf(" iProduct: %s\n", buffer); printf(" bcdDevice: %X.%02X (firmware release?)\n", dev->descriptor.bcdDevice >> 8, dev->descriptor.bcdDevice & 0xFF); usb_interface = get_ccid_usb_interface(dev)->altsetting; printf(" bLength: %d\n", usb_interface->bLength); printf(" bDescriptorType: %d\n", usb_interface->bDescriptorType); printf(" bInterfaceNumber: %d\n", usb_interface->bInterfaceNumber); printf(" bAlternateSetting: %d\n", usb_interface->bAlternateSetting); printf(" bNumEndpoints: %d\n", usb_interface->bNumEndpoints); switch (usb_interface->bNumEndpoints) { case 0: printf(" Control only\n"); break; case 1: printf(" Interrupt-IN\n"); break; case 2: printf(" bulk-IN and bulk-OUT\n"); break; case 3: printf(" bulk-IN, bulk-OUT and Interrupt-IN\n"); break; default: printf(" UNKNOWN value\n"); } printf(" bInterfaceClass: 0x%02X", usb_interface->bInterfaceClass); if (usb_interface->bInterfaceClass == 0x0b) printf(" [Chip Card Interface Device Class (CCID)]\n"); else { printf("\n NOT A CCID DEVICE\n"); if (usb_interface->bInterfaceClass != 0xFF) return TRUE; else printf(" Class is 0xFF (proprietary)\n"); } printf(" bInterfaceSubClass: %d\n", usb_interface->bInterfaceSubClass); if (usb_interface->bInterfaceSubClass) printf(" UNSUPPORTED SubClass\n"); printf(" bInterfaceProtocol: %d\n", usb_interface->bInterfaceProtocol); switch (usb_interface->bInterfaceProtocol) { case 0: printf(" bulk transfer, optional interrupt-IN\n"); break; case 1: printf(" ICCD Version A, Control transfers, (no interrupt-IN)\n"); break; case 2: printf(" ICCD Version B, Control transfers, (optional interrupt-IN)\n"); break; default: printf(" UNSUPPORTED InterfaceProtocol\n"); } printf(" iInterface: %d\n", usb_interface->iInterface); if (usb_interface->extralen < 54) { printf("USB extra length is too short: %d\n", usb_interface->extralen); printf("\n NOT A CCID DEVICE\n"); return TRUE; } /* * CCID Class Descriptor */ printf(" CCID Class Descriptor\n"); extra = usb_interface->extra; printf(" bLength: 0x%02X\n", extra[0]); if (extra[0] != 0x36) { printf(" UNSUPPORTED bLength\n"); return TRUE; } printf(" bDescriptorType: 0x%02X\n", extra[1]); if (extra[1] != 0x21) { if (0xFF == extra[1]) printf(" PROPRIETARY bDescriptorType\n"); else { printf(" UNSUPPORTED bDescriptorType\n"); return TRUE; } } printf(" bcdCCID: %X.%02X\n", extra[3], extra[2]); printf(" bMaxSlotIndex: 0x%02X\n", extra[4]); printf(" bVoltageSupport: 0x%02X\n", extra[5]); if (extra[5] & 0x01) printf(" 5.0V\n"); if (extra[5] & 0x02) printf(" 3.0V\n"); if (extra[5] & 0x04) printf(" 1.8V\n"); printf(" dwProtocols: 0x%02X%02X 0x%02X%02X\n", extra[9], extra[8], extra[7],extra[6]); if (extra[6] & 0x01) printf(" T=0\n"); if (extra[6] & 0x02) printf(" T=1\n"); printf(" dwDefaultClock: %.3f MHz\n", dw2i(extra, 10)/1000.0); printf(" dwMaximumClock: %.3f MHz\n", dw2i(extra, 14)/1000.0); printf(" bNumClockSupported: %d %s\n", extra[18], extra[18] ? "" : "(will use whatever is returned)"); { int n; /* See CCID 3.7.2 page 25 */ n = usb_control_msg(handle, 0xA1, /* request type */ 0x02, /* GET CLOCK FREQUENCIES */ 0x00, /* value */ usb_interface->bInterfaceNumber, /* interface */ buffer, sizeof(buffer), 2 * 1000); /* we got an error? */ if (n <= 0) { printf(" IFD does not support GET CLOCK FREQUENCIES request: %s\n", strerror(errno)); if (EBUSY == errno) { printf(" \33[01;31mPlease, stop pcscd and retry\33[0m\n\n"); return TRUE; } } else if (n % 4) /* not a multiple of 4 */ printf(" wrong size for GET CLOCK FREQUENCIES: %d\n", n); else { int i; /* we do not get the expected number of data rates */ if ((n != extra[18]*4) && extra[18]) { printf(" Got %d clock frequencies but was expecting %d\n", n/4, extra[18]); /* we got more data than expected */ if (n > extra[18]*4) n = extra[18]*4; } for (i=0; ibInterfaceNumber, /* interface */ buffer, sizeof(buffer), 2 * 1000); /* we got an error? */ if (n <= 0) printf(" IFD does not support GET_DATA_RATES request: %s\n", strerror(errno)); else if (n % 4) /* not a multiple of 4 */ printf(" wrong size for GET_DATA_RATES: %d\n", n); else { int i; /* we do not get the expected number of data rates */ if ((n != extra[27]*4) && extra[27]) { printf(" Got %d data rates but was expecting %d\n", n/4, extra[27]); /* we got more data than expected */ if (n > extra[27]*4) n = extra[27]*4; } for (i=0; i