Discussion:
[edk2] [PATCH 2/4] MdeModulePkg/SmartCardReader: Add files from pcsc-lite project
Ludovic Rousseau
2015-06-10 18:27:41 UTC
Permalink
pcsc-lite project is hosted at http://pcsclite.alioth.debian.org/pcsclite.html

The pcsc-lite project uses the BSD 3-clauses license. This license
should be compatible with the TianoCore Contribution Agreement 1.0 (but
I am not a lawyer).

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ludovic Rousseau <***@gmail.com>
---
MdeModulePkg/Library/SmartCardReader/ifdhandler.h | 825 ++++++++++++++++++++++
MdeModulePkg/Library/SmartCardReader/misc.h | 88 +++
MdeModulePkg/Library/SmartCardReader/pcsclite.h | 65 ++
MdeModulePkg/Library/SmartCardReader/reader.h | 285 ++++++++
MdeModulePkg/Library/SmartCardReader/wintypes.h | 120 ++++
5 files changed, 1383 insertions(+)
create mode 100644 MdeModulePkg/Library/SmartCardReader/ifdhandler.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/misc.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/pcsclite.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/reader.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/wintypes.h

diff --git a/MdeModulePkg/Library/SmartCardReader/ifdhandler.h b/MdeModulePkg/Library/SmartCardReader/ifdhandler.h
new file mode 100644
index 0000000..f47e018
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/ifdhandler.h
@@ -0,0 +1,825 @@
+/*
+ * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
+ *
+ * Copyright (C) 1999-2004
+ * David Corcoran <***@musclecard.com>
+ * Copyright (C) 2003-2004
+ * Damien Sauveron <***@labri.fr>
+ * Copyright (C) 2002-2011
+ * Ludovic Rousseau <***@free.fr>
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+Changes to this license can be made only by the copyright author with
+explicit written consent.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ifdhandler.h 6965 2014-09-01 14:52:42Z rousseau $
+ */
+
+/**
+ * @file
+ * @defgroup IFDHandler IFDHandler
+ * @brief This provides reader specific low-level calls.
+
+The routines specified hereafter will allow you to write an IFD handler
+for the PC/SC Lite resource manager. Please use the complement
+developer's kit complete with headers and Makefile at:
+http://www.musclecard.com/drivers.html
+
+This gives a common API for communication to most readers in a
+homogeneous fashion. This document assumes that the driver developer is
+experienced with standards such as ISO-7816-(1, 2, 3, 4), EMV and MCT
+specifications. For listings of these specifications please access the
+above web site.
+
+@section UsbReaders USB readers
+
+USB readers use the bundle approach so that the reader can be loaded
+and unloaded upon automatic detection of the device. The bundle
+approach is simple: the actual library is just embedded in a
+directory so additional information can be gathered about the device.
+
+A bundle looks like the following:
+
+@verbatim
+GenericReader.bundle/
+ Contents/
+ Info.plist - XML file describing the reader
+ MacOS/ - Driver directory for OS X
+ Solaris/ - Driver directory for Solaris
+ Linux/ - Driver directory for Linux
+ HPUX/ - Driver directory for HPUX
+@endverbatim
+
+The @c Info.plist file describes the driver and gives the loader
+all the necessary information. The following must be contained in the
+@c Info.plist file:
+
+@subsection ifdVendorID
+
+The vendor ID of the USB device.
+
+Example:
+
+@verbatim
+ <key>ifdVendorID</key>
+ <string>0x04E6</string>
+@endverbatim
+
+You may have an OEM of this reader in which an additional @c <string>
+can be used like in the below example:
+
+@verbatim
+ <key>ifdVendorID</key>
+ <array>
+ <string>0x04E6</string>
+ <string>0x0973</string>
+ </array>
+@endverbatim
+
+If multiples exist all the other parameters must have a second value
+also. You may chose not to support this feature but it is useful when
+reader vendors OEM products so you only distribute one driver.
+
+
+The CCID driver from Ludovic Rousseau
+http://pcsclite.alioth.debian.org/ccid.html uses this feature since the
+same driver supports many different readers.
+
+@subsection ifdProductID
+
+ The product id of the USB device.
+
+@verbatim
+ <key>ifdProductID</key>
+ <string>0x3437</string>
+@endverbatim
+
+@subsection ifdFriendlyName
+
+ Example:
+
+@verbatim
+ <key>ifdFriendlyName</key>
+ <string>SCM Microsystems USB Reader</string>
+@endverbatim
+
+@subsection CFBundleExecutable
+
+ The executable name which exists in the particular platform's directory.
+
+ Example:
+
+@verbatim
+ <key>CFBundleExecutable</key>
+ <string>libccid.so.0.4.2</string>
+@endverbatim
+
+@subsection ifdCapabilities
+
+ List of capabilities supported by the driver. This is a bit field. Possible values are:
+
+- 0
+ No special capabilities
+- 1 IFD_GENERATE_HOTPLUG
+ The driver supports the hot plug feature.
+
+Complete sample file:
+
+@verbatim
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>0.0.1d1</string>
+ <key>ifdCapabilities</key>
+ <string>0x00000000</string>
+ <key>ifdProtocolSupport</key>
+ <string>0x00000001</string>
+ <key>ifdVersionNumber</key>
+ <string>0x00000001</string>
+
+ <key>CFBundleExecutable</key>
+ <string>libfoobar.so.x.y</string>
+
+ <key>ifdManufacturerString</key>
+ <string>Foo bar inc.</string>
+
+ <key>ifdProductString</key>
+ <string>Driver for Foobar reader, version x.y</string>
+
+ <key>ifdVendorID</key>
+ <string>0x1234</string>
+
+ <key>ifdProductID</key>
+ <string>0x5678</string>
+
+ <key>ifdFriendlyName</key>
+ <string>Foobar USB reader</string>
+</dict>
+</plist>
+@endverbatim
+
+As indicated in the XML file the DTD is available at
+http://www.apple.com/DTDs/PropertyList-1.0.dtd.
+
+@section SerialReaders Serial readers
+
+Serial drivers must be configured to operate on a particular port and
+respond to a particular name. The @c reader.conf file is used for this
+purpose.
+
+It has the following syntax:
+
+@verbatim
+# Configuration file for pcsc-lite
+# David Corcoran <***@musclecard.com>
+
+FRIENDLYNAME Generic Reader
+DEVICENAME /dev/ttyS0
+LIBPATH /usr/lib/pcsc/drivers/libgen_ifd.so
+CHANNELID 1
+@endverbatim
+
+The pound sign # denotes a comment.
+
+@subsection FRIENDLYNAME
+The FRIENDLYNAME field is an arbitrary text used to identify the reader.
+This text is displayed by commands like @c pcsc_scan
+http://ludovic.rousseau.free.fr/softwares/pcsc-tools/ that prints the
+names of all the connected and detected readers.
+
+@subsection DEVICENAME
+The DEVICENAME field was not used for old drivers (using the IFD handler
+version 2.0 or previous). It is now (IFD handler version 3.0) used to
+identify the physical port on which the reader is connected. This is
+the device name of this port. It is dependent of the OS kernel. For
+example the first serial port device is called @c /dev/ttyS0 under Linux
+and @c /dev/cuaa0 under FreeBSD.
+
+If you want to use IFDHCreateChannel() instead of
+IFDHCreateChannelByName() then do not use any DEVICENAME line in the
+configuration file. IFDHCreateChannel() will then be called with the
+CHANNELID parameter.
+
+@subsection LIBPATH
+The LIBPATH field is the filename of the driver code. The driver is a
+dynamically loaded piece of code (generally a @c drivername.so* file).
+
+@subsection CHANNELID
+The CHANNELID is no more used for recent drivers (IFD handler 3.0) and
+has been superseded by DEVICENAME.
+
+If you have an old driver this field is used to indicate the port to
+use. You should read your driver documentation to know what information
+is needed here. It should be the serial port number for a serial reader.
+
+CHANNELID was the numeric version of the port in which the reader will
+be located. This may be done by a symbolic link where @c /dev/pcsc/1 is
+the first device which may be a symbolic link to @c /dev/ttyS0 or
+whichever location your reader resides.
+
+ */
+
+#ifndef _ifd_handler_h_
+#define _ifd_handler_h_
+
+#include <wintypes.h>
+#define MAX_ATR_SIZE 33 /* from pcsclite.h */
+
+ /*
+ * List of data structures available to ifdhandler
+ */
+ typedef struct _DEVICE_CAPABILITIES
+ {
+ LPSTR Vendor_Name; /**< Tag 0x0100 */
+ LPSTR IFD_Type; /**< Tag 0x0101 */
+ DWORD IFD_Version; /**< Tag 0x0102 */
+ LPSTR IFD_Serial; /**< Tag 0x0103 */
+ DWORD IFD_Channel_ID; /**< Tag 0x0110 */
+
+ DWORD Asynch_Supported; /**< Tag 0x0120 */
+ DWORD Default_Clock; /**< Tag 0x0121 */
+ DWORD Max_Clock; /**< Tag 0x0122 */
+ DWORD Default_Data_Rate; /**< Tag 0x0123 */
+ DWORD Max_Data_Rate; /**< Tag 0x0124 */
+ DWORD Max_IFSD; /**< Tag 0x0125 */
+ DWORD Synch_Supported; /**< Tag 0x0126 */
+ DWORD Power_Mgmt; /**< Tag 0x0131 */
+ DWORD Card_Auth_Devices; /**< Tag 0x0140 */
+ DWORD User_Auth_Device; /**< Tag 0x0142 */
+ DWORD Mechanics_Supported; /**< Tag 0x0150 */
+ DWORD Vendor_Features; /**< Tag 0x0180 - 0x01F0 User Defined. */
+ }
+ DEVICE_CAPABILITIES, *PDEVICE_CAPABILITIES;
+
+ typedef struct _ICC_STATE
+ {
+ UCHAR ICC_Presence; /**< Tag 0x0300 */
+ UCHAR ICC_Interface_Status; /**< Tag 0x0301 */
+ UCHAR ATR[MAX_ATR_SIZE]; /**< Tag 0x0303 */
+ UCHAR ICC_Type; /**< Tag 0x0304 */
+ }
+ ICC_STATE, *PICC_STATE;
+
+ typedef struct _PROTOCOL_OPTIONS
+ {
+ DWORD Protocol_Type; /**< Tag 0x0201 */
+ DWORD Current_Clock; /**< Tag 0x0202 */
+ DWORD Current_F; /**< Tag 0x0203 */
+ DWORD Current_D; /**< Tag 0x0204 */
+ DWORD Current_N; /**< Tag 0x0205 */
+ DWORD Current_W; /**< Tag 0x0206 */
+ DWORD Current_IFSC; /**< Tag 0x0207 */
+ DWORD Current_IFSD; /**< Tag 0x0208 */
+ DWORD Current_BWT; /**< Tag 0x0209 */
+ DWORD Current_CWT; /**< Tag 0x020A */
+ DWORD Current_EBC; /**< Tag 0x020B */
+ }
+ PROTOCOL_OPTIONS, *PPROTOCOL_OPTIONS;
+
+ /**
+ * Use by SCardTransmit()
+ */
+ typedef struct _SCARD_IO_HEADER
+ {
+ DWORD Protocol;
+ DWORD Length;
+ }
+ SCARD_IO_HEADER, *PSCARD_IO_HEADER;
+
+ /*
+ * The list of tags should be alot more but this is all I use in the
+ * meantime
+ */
+#define TAG_IFD_ATR 0x0303 /**< ATR */
+#define TAG_IFD_SLOTNUM 0x0180 /**< select a slot */
+#define TAG_IFD_SLOT_THREAD_SAFE 0x0FAC /**< support access to different slots of the reader */
+#define TAG_IFD_THREAD_SAFE 0x0FAD /**< driver is thread safe */
+#define TAG_IFD_SLOTS_NUMBER 0x0FAE /**< number of slots of the reader */
+#define TAG_IFD_SIMULTANEOUS_ACCESS 0x0FAF /**< number of reader the driver can manage */
+#define TAG_IFD_POLLING_THREAD 0x0FB0 /**< not used. See TAG_IFD_POLLING_THREAD_WITH_TIMEOUT */
+#define TAG_IFD_POLLING_THREAD_KILLABLE 0x0FB1 /**< the polling thread can be killed */
+#define TAG_IFD_STOP_POLLING_THREAD 0x0FB2 /**< method used to stop the polling thread (instead of just pthread_kill()) */
+#define TAG_IFD_POLLING_THREAD_WITH_TIMEOUT 0x0FB3 /**< driver uses a polling thread with a timeout parameter */
+
+ /*
+ * IFD Handler version number enummerations
+ */
+#define IFD_HVERSION_1_0 0x00010000
+#define IFD_HVERSION_2_0 0x00020000
+#define IFD_HVERSION_3_0 0x00030000
+
+ /*
+ * List of defines available to ifdhandler
+ */
+#define IFD_POWER_UP 500 /**< power up the card */
+#define IFD_POWER_DOWN 501 /**< power down the card */
+#define IFD_RESET 502 /**< warm reset */
+
+#define IFD_NEGOTIATE_PTS1 1 /**< negotiate PTS1 */
+#define IFD_NEGOTIATE_PTS2 2 /**< negotiate PTS2 */
+#define IFD_NEGOTIATE_PTS3 4 /**< negotiate PTS3 */
+
+#define IFD_SUCCESS 0 /**< no error */
+#define IFD_ERROR_TAG 600 /**< tag unknown */
+#define IFD_ERROR_SET_FAILURE 601 /**< set failed */
+#define IFD_ERROR_VALUE_READ_ONLY 602 /**< value is read only */
+#define IFD_ERROR_PTS_FAILURE 605 /**< failed to negotiate PTS */
+#define IFD_ERROR_NOT_SUPPORTED 606
+#define IFD_PROTOCOL_NOT_SUPPORTED 607 /**< requested protocol not supported */
+#define IFD_ERROR_POWER_ACTION 608 /**< power up failed */
+#define IFD_ERROR_SWALLOW 609
+#define IFD_ERROR_EJECT 610
+#define IFD_ERROR_CONFISCATE 611
+#define IFD_COMMUNICATION_ERROR 612 /**< generic error */
+#define IFD_RESPONSE_TIMEOUT 613 /**< timeout */
+#define IFD_NOT_SUPPORTED 614 /**< request is not supported */
+#define IFD_ICC_PRESENT 615 /**< card is present */
+#define IFD_ICC_NOT_PRESENT 616 /**< card is absent */
+/**
+ * The \ref IFD_NO_SUCH_DEVICE error must be returned by the driver when
+ * it detects the reader is no more present. This will tell pcscd to
+ * remove the reader from the list of available readers.
+ */
+#define IFD_NO_SUCH_DEVICE 617
+#define IFD_ERROR_INSUFFICIENT_BUFFER 618 /**< buffer is too small */
+
+#ifndef RESPONSECODE_DEFINED_IN_WINTYPES_H
+ typedef long RESPONSECODE;
+#endif
+
+ /*
+ * If you want to compile a V2.0 IFDHandler, define IFDHANDLERv2
+ * before you include this file.
+ *
+ * By default it is setup for for most recent version of the API (V3.0)
+ */
+
+#ifndef IFDHANDLERv2
+
+ /*
+ * List of Defined Functions Available to IFD_Handler 3.0
+ *
+ * All the functions of IFD_Handler 2.0 are available
+ * IFDHCreateChannelByName() is new
+ * IFDHControl() API changed
+ */
+
+/**
+This function is required to open a communications channel to the port
+listed by @p DeviceName.
+
+Once the channel is opened the reader must be in a state in which it is
+possible to query IFDHICCPresence() for card status.
+
+@ingroup IFDHandler
+@param[in] Lun Logical Unit Number\n
+ Use this for multiple card slots or multiple readers. 0xXXXXYYYY -
+ XXXX multiple readers, YYYY multiple slots. The resource manager will
+ set these automatically. By default the resource manager loads a new
+ instance of the driver so if your reader does not have more than one
+ smart card slot then ignore the Lun in all the functions.\n
+ \n
+ PC/SC supports the loading of multiple readers through one instance of
+ the driver in which XXXX is important. XXXX identifies the unique
+ reader in which the driver communicates to. The driver should set up
+ an array of structures that asociate this XXXX with the underlying
+ details of the particular reader.
+
+@param[in] DeviceName Filename to use by the driver.\n
+ For drivers configured by @p /etc/reader.conf this is the value of the
+ field \ref DEVICENAME.
+ \n
+ For USB drivers the @p DeviceName must start with @p usb:VID/PID. VID
+ is the Vendor ID and PID is the Product ID. Both are a 4-digits hex
+ number.
+
+Typically the string is generated by:
+
+@code
+printf("usb:%04x/%04x", idVendor, idProduct);
+@endcode
+
+The @p DeviceName string may also contain a more specialised
+identification string. This additional information is used to
+differentiate between two identical readers connected at the same time.
+In this case the driver can't differentiate the two readers using VID
+and PID and must use some additional information identifying the USB
+port used by each reader.
+
+- libusb
+
+ For USB drivers using libusb-1.0 http://libusb.sourceforge.net/ for USB
+ abstraction the @p DeviceName the string may be generated by:
+
+ @code
+ printf("usb:%04x/%04x:libusb-1.0:%d:%d:%d",
+ idVendor, idProduct, bus_number, device_address, interface)
+ @endcode
+
+ So it is something like: <tt>usb:08e6/3437:libusb-1.0:7:99:0</tt> under
+ GNU/Linux.
+
+- libudev
+
+ If pcscd is compiled with libudev support instead of libusb (default
+ since pcsc-lite 1.6.8) the string will look like:
+
+ @code
+ printf("usb:%04x/%04x:libudev:%d:%s", idVendor, idProduct,
+ bInterfaceNumber, devpath);
+ @endcode
+
+ bInterfaceNumber is the number of the interface on the device. It is
+ only usefull for devices with more than one CCID interface.
+
+ devpath is the filename of the device on the file system.
+
+ So it is something like:
+ <tt>usb:08e6/3437:libudev:0:/dev/bus/usb/008/047</tt>
+ under GNU/Linux.
+
+- other
+
+ If the driver does not understand the <tt>:libusb:</tt> or
+ <tt>:libudev:</tt> scheme or if a new scheme is used, the driver should
+ ignore the part it does not understand instead of failing.
+
+ The driver shall recognize the <tt>usb:VID/PID</tt> part and, only if
+ possible, the remaining of the DeviceName field.
+
+ It is the responsibility of the driver to correctly identify the reader.
+
+@return Error codes
+@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS)
+@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR)
+@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE)
+ */
+RESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR DeviceName);
+
+/**
+This function performs a data exchange with the reader (not the card)
+specified by Lun. It is responsible for abstracting functionality such
+as PIN pads, biometrics, LCD panels, etc. You should follow the MCT and
+CTBCS specifications for a list of accepted commands to implement. This
+function is fully voluntary and does not have to be implemented unless
+you want extended functionality.
+
+@ingroup IFDHandler
+@param[in] Lun Logical Unit Number
+@param[in] dwControlCode Control code for the operation\n
+ This value identifies the specific operation to be performed. This
+ value is driver specific.
+@param[in] TxBuffer Transmit data
+@param[in] TxLength Length of this buffer
+@param[out] RxBuffer Receive data
+@param[in] RxLength Length of the response buffer
+@param[out] pdwBytesReturned Length of response\n
+ This function will be passed the length of the buffer RxBuffer in
+ RxLength and it must set the length of the received data in
+ pdwBytesReturned.
+
+@note
+ @p *pdwBytesReturned should be set to zero on error.
+
+@return Error codes
+@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS)
+@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR)
+@retval IFD_RESPONSE_TIMEOUT The response timed out (\ref IFD_RESPONSE_TIMEOUT)
+@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE)
+ */
+RESPONSECODE IFDHControl(DWORD Lun, DWORD dwControlCode, PUCHAR
+ TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength,
+ LPDWORD pdwBytesReturned);
+
+#else
+
+/**
+ * Available in IFD_Handler 2.0
+ *
+ * @deprecated
+ * You should use the new form of IFDHControl()
+ */
+RESPONSECODE IFDHControl(DWORD Lun, PUCHAR TxBuffer, DWORD TxLength,
+ PUCHAR RxBuffer, PDWORD RxLength);
+
+#endif
+
+ /*
+ * common functions in IFD_Handler 2.0 and 3.0
+ */
+/**
+This function is required to open a communications channel to the port
+listed by Channel. For example, the first serial reader on COM1 would
+link to @p /dev/pcsc/1 which would be a symbolic link to @p /dev/ttyS0
+on some machines This is used to help with inter-machine independence.
+
+On machines with no /dev directory the driver writer may choose to map
+their Channel to whatever they feel is appropriate.
+
+Once the channel is opened the reader must be in a state in which it is
+possible to query IFDHICCPresence() for card status.
+
+USB readers can ignore the @p Channel parameter and query the USB bus
+for the particular reader by manufacturer and product id.
+
+@ingroup IFDHandler
+@param[in] Lun Logical Unit Number\n
+ Use this for multiple card slots or multiple readers. 0xXXXXYYYY -
+ XXXX multiple readers, YYYY multiple slots. The resource manager will
+ set these automatically. By default the resource manager loads a new
+ instance of the driver so if your reader does not have more than one
+ smart card slot then ignore the Lun in all the functions.\n
+ \n
+ PC/SC supports the loading of multiple readers through one instance of
+ the driver in which XXXX is important. XXXX identifies the unique
+ reader in which the driver communicates to. The driver should set up
+ an array of structures that associate this XXXX with the underlying
+ details of the particular reader.
+@param[in] Channel Channel ID
+ This is denoted by the following:
+ - 0x000001 @p /dev/pcsc/1
+ - 0x000002 @p /dev/pcsc/2
+ - 0x000003 @p /dev/pcsc/3
+ - 0x000004 @p /dev/pcsc/4
+
+@return Error codes
+@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS)
+@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR)
+@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE)
+
+ */
+RESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel);
+
+/**
+This function should close the reader communication channel for the
+particular reader. Prior to closing the communication channel the reader
+should make sure the card is powered down and the terminal is also
+powered down.
+
+@ingroup IFDHandler
+@param[in] Lun Logical Unit Number
+
+@return Error codes
+@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS)
+@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR)
+@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE)
+ */
+RESPONSECODE IFDHCloseChannel(DWORD Lun);
+
+/**
+This function should get the slot/card capabilities for a particular
+slot/card specified by Lun. Again, if you have only 1 card slot and
+don't mind loading a new driver for each reader then ignore Lun.
+
+@ingroup IFDHandler
+@param[in] Lun Logical Unit Number
+@param[in] Tag Tag of the desired data value
+- \ref TAG_IFD_ATR
+ Return the ATR and its size (implementation is mandatory).
+- \ref TAG_IFD_SLOTNUM
+ Unused/deprecated
+- \ref SCARD_ATTR_ATR_STRING
+ Same as \ref TAG_IFD_ATR but this one is not mandatory. It is defined
+ in Microsoft PC/SC SCardGetAttrib().
+- \ref TAG_IFD_SIMULTANEOUS_ACCESS
+ Return the number of sessions (readers) the driver can handle in
+ <tt>Value[0]</tt>.
+ This is used for multiple readers sharing the same driver.
+- \ref TAG_IFD_THREAD_SAFE
+ If the driver supports more than one reader (see
+ \ref TAG_IFD_SIMULTANEOUS_ACCESS above) this tag indicates if the
+ driver supports access to multiple readers at the same time.\n
+ <tt>Value[0] = 1</tt> indicates the driver supports simultaneous accesses.
+- \ref TAG_IFD_SLOTS_NUMBER
+ Return the number of slots in this reader in <tt>Value[0]</tt>.
+- \ref TAG_IFD_SLOT_THREAD_SAFE
+ If the reader has more than one slot (see \ref TAG_IFD_SLOTS_NUMBER
+ above) this tag indicates if the driver supports access to multiple
+ slots of the same reader at the same time.\n
+ <tt>Value[0] = 1</tt> indicates the driver supports simultaneous slot
+ accesses.
+- \ref TAG_IFD_POLLING_THREAD
+ Unused/deprecated
+- \ref TAG_IFD_POLLING_THREAD_WITH_TIMEOUT
+ If the driver provides a polling thread then @p Value is a pointer to
+ this function. The function prototype is:
+@verbatim
+ RESPONSECODE foo(DWORD Lun, int timeout);
+@endverbatim
+- \ref TAG_IFD_POLLING_THREAD_KILLABLE
+ Tell if the polling thread can be killed (pthread_kill()) by pcscd
+- \ref TAG_IFD_STOP_POLLING_THREAD
+ Returns a pointer in @p Value to the function used to stop the polling
+ thread returned by \ref TAG_IFD_POLLING_THREAD_WITH_TIMEOUT. The
+ function prototype is:
+@verbatim
+ RESPONSECODE foo(DWORD Lun);
+@endverbatim
+@param[in,out] Length Length of the desired data value
+@param[out] Value Value of the desired data
+
+@return Error codes
+@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS)
+@retval IFD_ERROR_TAG Invalid tag given (\ref IFD_ERROR_TAG)
+@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE)
+ */
+RESPONSECODE IFDHGetCapabilities(DWORD Lun, DWORD Tag, PDWORD Length,
+ PUCHAR Value);
+
+/**
+This function should set the slot/card capabilities for a particular
+slot/card specified by @p Lun. Again, if you have only 1 card slot and
+don't mind loading a new driver for each reader then ignore @p Lun.
+
+@ingroup IFDHandler
+@param[in] Lun Logical Unit Number
+@param[in] Tag Tag of the desired data value
+@param[in,out] Length Length of the desired data value
+@param[out] Value Value of the desired data
+
+This function is also called when the application uses the PC/SC
+SCardGetAttrib() function. The list of supported tags is not limited.
+
+@return Error codes
+@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS)
+@retval IFD_ERROR_TAG Invalid tag given (\ref IFD_ERROR_TAG)
+@retval IFD_ERROR_SET_FAILURE Could not set value (\ref IFD_ERROR_SET_FAILURE)
+@retval IFD_ERROR_VALUE_READ_ONLY Trying to set read only value (\ref IFD_ERROR_VALUE_READ_ONLY)
+@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE)
+ */
+RESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag, DWORD Length, PUCHAR Value);
+
+/**
+This function should set the Protocol Type Selection (PTS) of a
+particular card/slot using the three PTS parameters sent
+
+@ingroup IFDHandler
+@param[in] Lun Logical Unit Number
+@param[in] Protocol Desired protocol
+- \ref SCARD_PROTOCOL_T0
+ T=0 protocol
+- \ref SCARD_PROTOCOL_T1
+ T=1 protocol
+@param[in] Flags Logical OR of possible values to determine which PTS values
+to negotiate
+- \ref IFD_NEGOTIATE_PTS1
+- \ref IFD_NEGOTIATE_PTS2
+- \ref IFD_NEGOTIATE_PTS3
+@param[in] PTS1 1st PTS Value
+@param[in] PTS2 2nd PTS Value
+@param[in] PTS3 3rd PTS Value\n
+ See ISO 7816/EMV documentation.
+
+@return Error codes
+@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS)
+@retval IFD_ERROR_PTS_FAILURE Could not set PTS value (\ref IFD_ERROR_PTS_FAILURE)
+@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR)
+@retval IFD_PROTOCOL_NOT_SUPPORTED Protocol is not supported (\ref IFD_PROTOCOL_NOT_SUPPORTED)
+@retval IFD_NOT_SUPPORTED Action not supported (\ref IFD_NOT_SUPPORTED)
+@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE)
+ */
+RESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol, UCHAR Flags,
+ UCHAR PTS1, UCHAR PTS2, UCHAR PTS3);
+/**
+This function controls the power and reset signals of the smart card
+reader at the particular reader/slot specified by @p Lun.
+
+@ingroup IFDHandler
+@param[in] Lun Logical Unit Number
+@param[in] Action Action to be taken on the card
+- \ref IFD_POWER_UP
+ Power up the card (store and return Atr and AtrLength)
+- \ref IFD_POWER_DOWN
+ Power down the card (Atr and AtrLength should be zeroed)
+- \ref IFD_RESET
+ Perform a warm reset of the card (no power down). If the card is not powered then power up the card (store and return Atr and AtrLength)
+@param[out] Atr Answer to Reset (ATR) of the card\n
+ The driver is responsible for caching this value in case
+ IFDHGetCapabilities() is called requesting the ATR and its length. The
+ ATR length should not exceed \ref MAX_ATR_SIZE.
+@param[in,out] AtrLength Length of the ATR\n
+ This should not exceed \ref MAX_ATR_SIZE.
+
+@note
+Memory cards without an ATR should return \ref IFD_SUCCESS on reset but the
+Atr should be zeroed and the length should be zero Reset errors should
+return zero for the AtrLength and return \ref IFD_ERROR_POWER_ACTION.
+
+@return Error codes
+@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS)
+@retval IFD_ERROR_POWER_ACTION Error powering/resetting card (\ref IFD_ERROR_POWER_ACTION)
+@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR)
+@retval IFD_NOT_SUPPORTED Action not supported (\ref IFD_NOT_SUPPORTED)
+@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE)
+ */
+RESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action, PUCHAR Atr, PDWORD
+ AtrLength);
+
+/**
+This function performs an APDU exchange with the card/slot specified by
+Lun. The driver is responsible for performing any protocol specific
+exchanges such as T=0, 1, etc. differences. Calling this function will
+abstract all protocol differences.
+
+@ingroup IFDHandler
+@param[in] Lun Logical Unit Number
+@param[in] SendPci contains two structure members
+- Protocol 0, 1, ... 14\n
+ T=0 ... T=14
+- Length\n
+ Not used.
+@param[in] TxBuffer Transmit APDU\n
+ Example: "\x00\xA4\x00\x00\x02\x3F\x00"
+@param[in] TxLength Length of this buffer
+@param[out] RxBuffer Receive APDU\n
+ Example: "\x61\x14"
+@param[in,out] RxLength Length of the received APDU\n
+ This function will be passed the size of the buffer of RxBuffer and
+ this function is responsible for setting this to the length of the
+ received APDU response. This should be ZERO on all errors. The
+ resource manager will take responsibility of zeroing out any temporary
+ APDU buffers for security reasons.
+@param[out] RecvPci contains two structure members
+- Protocol - 0, 1, ... 14\n
+ T=0 ... T=14
+- Length\n
+ Not used.
+
+@note
+The driver is responsible for knowing what type of card it has. If the
+current slot/card contains a memory card then this command should ignore
+the Protocol and use the MCT style commands for support for these style
+cards and transmit them appropriately. If your reader does not support
+memory cards or you don't want to implement this functionality, then
+ignore this.
+@par
+RxLength should be set to zero on error.
+@par
+The driver is not responsible for doing an automatic Get Response
+command for received buffers containing 61 XX.
+
+@return Error codes
+@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS)
+@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR)
+@retval IFD_RESPONSE_TIMEOUT The response timed out (\ref IFD_RESPONSE_TIMEOUT)
+@retval IFD_ICC_NOT_PRESENT ICC is not present (\ref IFD_ICC_NOT_PRESENT)
+@retval IFD_NOT_SUPPORTED Action not supported (\ref IFD_NOT_SUPPORTED)
+@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE)
+ */
+RESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci,
+ PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, PDWORD
+ RxLength, PSCARD_IO_HEADER RecvPci);
+
+/**
+This function returns the status of the card inserted in the reader/slot
+specified by @p Lun. In cases where the device supports asynchronous
+card insertion/removal detection, it is advised that the driver manages
+this through a thread so the driver does not have to send and receive a
+command each time this function is called.
+
+@ingroup IFDHandler
+@param[in] Lun Logical Unit Number
+
+@return Error codes
+@retval IFD_SUCCESS Successful (\ref IFD_SUCCESS)
+@retval IFD_COMMUNICATION_ERROR Error has occurred (\ref IFD_COMMUNICATION_ERROR)
+@retval IFD_ICC_NOT_PRESENT ICC is not present (\ref IFD_ICC_NOT_PRESENT)
+@retval IFD_NO_SUCH_DEVICE The reader is no more present (\ref IFD_NO_SUCH_DEVICE)
+ */
+RESPONSECODE IFDHICCPresence(DWORD Lun);
+
+void SetReaderName(DWORD Lun, CHAR16 *ReaderName);
+#endif
diff --git a/MdeModulePkg/Library/SmartCardReader/misc.h b/MdeModulePkg/Library/SmartCardReader/misc.h
new file mode 100644
index 0000000..b5f32af
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/misc.h
@@ -0,0 +1,88 @@
+/*
+ * This handles GCC attributes
+ *
+ * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
+ *
+ * Copyright (C) 2005-2010
+ * Ludovic Rousseau <***@free.fr>
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+Changes to this license can be made only by the copyright author with
+explicit written consent.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: misc.h 6851 2014-02-14 15:43:32Z rousseau $
+ */
+
+#ifndef __misc_h__
+#define __misc_h__
+
+/*
+ * Declare the function as internal to the library: the function name is
+ * not exported and can't be used by a program linked to the library
+ *
+ * see http://gcc.gnu.org/onlinedocs/gcc-3.3.5/gcc/Function-Attributes.html#Function-Attributes
+ * see http://www.nedprod.com/programs/gccvisibility.html
+ */
+#if defined __GNUC__ && (! defined (__sun)) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
+#define INTERNAL __attribute__ ((visibility("hidden")))
+#define PCSC_API __attribute__ ((visibility("default")))
+#elif (! defined __GNUC__ ) && defined (__sun)
+/* http://wikis.sun.com/display/SunStudio/Macros+for+Shared+Library+Symbol+Visibility */
+#define INTERNAL __hidden
+#define PCSC_API __global
+#else
+#define INTERNAL
+#define PCSC_API
+#endif
+#define EXTERNAL PCSC_API
+
+#if defined __GNUC__
+
+/* GNU Compiler Collection (GCC) */
+#define CONSTRUCTOR __attribute__ ((constructor))
+#define DESTRUCTOR __attribute__ ((destructor))
+
+#else
+
+/* SUN C compiler does not use __attribute__ but #pragma init (function)
+ * We can't use a # inside a #define so it is not possible to use
+ * #define CONSTRUCTOR_DECLARATION(x) #pragma init (x)
+ * The #pragma is used directly where needed */
+
+/* any other */
+#define CONSTRUCTOR
+#define DESTRUCTOR
+
+#endif
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef COUNT_OF
+#define COUNT_OF(arr) (sizeof(arr)/sizeof(arr[0]))
+#endif
+
+#endif /* __misc_h__ */
diff --git a/MdeModulePkg/Library/SmartCardReader/pcsclite.h b/MdeModulePkg/Library/SmartCardReader/pcsclite.h
new file mode 100644
index 0000000..051e367
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/pcsclite.h
@@ -0,0 +1,65 @@
+/*
+ * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
+ *
+ * Copyright (C) 1999-2004
+ * David Corcoran <***@musclecard.com>
+ * Copyright (C) 2002-2011
+ * Ludovic Rousseau <***@free.fr>
+ * Copyright (C) 2005
+ * Martin Paljak <***@paljak.pri.ee>
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+Changes to this license can be made only by the copyright author with
+explicit written consent.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: pcsclite.h.in 6851 2014-02-14 15:43:32Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This keeps a list of defines for pcsc-lite.
+ *
+ */
+
+#ifndef __pcsclite_h__
+#define __pcsclite_h__
+
+#include <wintypes.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define MAX_ATR_SIZE 33 /**< Maximum ATR size */
+
+#define SCARD_PROTOCOL_T0 0x0001 /**< T=0 active protocol. */
+#define SCARD_PROTOCOL_T1 0x0002 /**< T=1 active protocol. */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/MdeModulePkg/Library/SmartCardReader/reader.h b/MdeModulePkg/Library/SmartCardReader/reader.h
new file mode 100644
index 0000000..1e82b70
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/reader.h
@@ -0,0 +1,285 @@
+/*
+ * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
+ *
+ * Copyright (C) 1999-2005
+ * David Corcoran <***@musclecard.com>
+ * Copyright (C) 2005-2009
+ * Ludovic Rousseau <***@free.fr>
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+Changes to this license can be made only by the copyright author with
+explicit written consent.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: reader.h 6851 2014-02-14 15:43:32Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This keeps a list of defines shared between the driver and the application
+ */
+
+#ifndef __reader_h__
+#define __reader_h__
+
+/*
+ * Tags for requesting card and reader attributes
+ */
+
+#define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag)))
+
+#define SCARD_CLASS_VENDOR_INFO 1 /**< Vendor information definitions */
+#define SCARD_CLASS_COMMUNICATIONS 2 /**< Communication definitions */
+#define SCARD_CLASS_PROTOCOL 3 /**< Protocol definitions */
+#define SCARD_CLASS_POWER_MGMT 4 /**< Power Management definitions */
+#define SCARD_CLASS_SECURITY 5 /**< Security Assurance definitions */
+#define SCARD_CLASS_MECHANICAL 6 /**< Mechanical characteristic definitions */
+#define SCARD_CLASS_VENDOR_DEFINED 7 /**< Vendor specific definitions */
+#define SCARD_CLASS_IFD_PROTOCOL 8 /**< Interface Device Protocol options */
+#define SCARD_CLASS_ICC_STATE 9 /**< ICC State specific definitions */
+#define SCARD_CLASS_SYSTEM 0x7fff /**< System-specific definitions */
+
+#define SCARD_ATTR_VENDOR_NAME SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0100) /**< Vendor name. */
+#define SCARD_ATTR_VENDOR_IFD_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0101) /**< Vendor-supplied interface device type (model designation of reader). */
+#define SCARD_ATTR_VENDOR_IFD_VERSION SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0102) /**< Vendor-supplied interface device version (DWORD in the form 0xMMmmbbbb where MM = major version, mm = minor version, and bbbb = build number). */
+#define SCARD_ATTR_VENDOR_IFD_SERIAL_NO SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0103) /**< Vendor-supplied interface device serial number. */
+#define SCARD_ATTR_CHANNEL_ID SCARD_ATTR_VALUE(SCARD_CLASS_COMMUNICATIONS, 0x0110) /**< DWORD encoded as 0xDDDDCCCC, where DDDD = data channel type and CCCC = channel number */
+#define SCARD_ATTR_ASYNC_PROTOCOL_TYPES SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0120) /**< FIXME */
+#define SCARD_ATTR_DEFAULT_CLK SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0121) /**< Default clock rate, in kHz. */
+#define SCARD_ATTR_MAX_CLK SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0122) /**< Maximum clock rate, in kHz. */
+#define SCARD_ATTR_DEFAULT_DATA_RATE SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0123) /**< Default data rate, in bps. */
+#define SCARD_ATTR_MAX_DATA_RATE SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0124) /**< Maximum data rate, in bps. */
+#define SCARD_ATTR_MAX_IFSD SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0125) /**< Maximum bytes for information file size device. */
+#define SCARD_ATTR_SYNC_PROTOCOL_TYPES SCARD_ATTR_VALUE(SCARD_CLASS_PROTOCOL, 0x0126) /**< FIXME */
+#define SCARD_ATTR_POWER_MGMT_SUPPORT SCARD_ATTR_VALUE(SCARD_CLASS_POWER_MGMT, 0x0131) /**< Zero if device does not support power down while smart card is inserted. Nonzero otherwise. */
+#define SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE SCARD_ATTR_VALUE(SCARD_CLASS_SECURITY, 0x0140) /**< FIXME */
+#define SCARD_ATTR_USER_AUTH_INPUT_DEVICE SCARD_ATTR_VALUE(SCARD_CLASS_SECURITY, 0x0142) /**< FIXME */
+#define SCARD_ATTR_CHARACTERISTICS SCARD_ATTR_VALUE(SCARD_CLASS_MECHANICAL, 0x0150) /**< DWORD indicating which mechanical characteristics are supported. If zero, no special characteristics are supported. Note that multiple bits can be set */
+
+#define SCARD_ATTR_CURRENT_PROTOCOL_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0201) /**< FIXME */
+#define SCARD_ATTR_CURRENT_CLK SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0202) /**< Current clock rate, in kHz. */
+#define SCARD_ATTR_CURRENT_F SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0203) /**< Clock conversion factor. */
+#define SCARD_ATTR_CURRENT_D SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0204) /**< Bit rate conversion factor. */
+#define SCARD_ATTR_CURRENT_N SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0205) /**< Current guard time. */
+#define SCARD_ATTR_CURRENT_W SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0206) /**< Current work waiting time. */
+#define SCARD_ATTR_CURRENT_IFSC SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0207) /**< Current byte size for information field size card. */
+#define SCARD_ATTR_CURRENT_IFSD SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0208) /**< Current byte size for information field size device. */
+#define SCARD_ATTR_CURRENT_BWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x0209) /**< Current block waiting time. */
+#define SCARD_ATTR_CURRENT_CWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020a) /**< Current character waiting time. */
+#define SCARD_ATTR_CURRENT_EBC_ENCODING SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020b) /**< Current error block control encoding. */
+#define SCARD_ATTR_EXTENDED_BWT SCARD_ATTR_VALUE(SCARD_CLASS_IFD_PROTOCOL, 0x020c) /**< FIXME */
+
+#define SCARD_ATTR_ICC_PRESENCE SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0300) /**< Single byte indicating smart card presence */
+#define SCARD_ATTR_ICC_INTERFACE_STATUS SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0301) /**< Single byte. Zero if smart card electrical contact is not active; nonzero if contact is active. */
+#define SCARD_ATTR_CURRENT_IO_STATE SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0302) /**< FIXME */
+#define SCARD_ATTR_ATR_STRING SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0303) /**< Answer to reset (ATR) string. */
+#define SCARD_ATTR_ICC_TYPE_PER_ATR SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0304) /**< Single byte indicating smart card type */
+
+#define SCARD_ATTR_ESC_RESET SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA000) /**< FIXME */
+#define SCARD_ATTR_ESC_CANCEL SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA003) /**< FIXME */
+#define SCARD_ATTR_ESC_AUTHREQUEST SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA005) /**< FIXME */
+#define SCARD_ATTR_MAXINPUT SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_DEFINED, 0xA007) /**< FIXME */
+
+#define SCARD_ATTR_DEVICE_UNIT SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0001) /**< Instance of this vendor's reader attached to the computer. The first instance will be device unit 0, the next will be unit 1 (if it is the same brand of reader) and so on. Two different brands of readers will both have zero for this value. */
+#define SCARD_ATTR_DEVICE_IN_USE SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0002) /**< Reserved for future use. */
+#define SCARD_ATTR_DEVICE_FRIENDLY_NAME_A SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0003)
+#define SCARD_ATTR_DEVICE_SYSTEM_NAME_A SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0004)
+#define SCARD_ATTR_DEVICE_FRIENDLY_NAME_W SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0005)
+#define SCARD_ATTR_DEVICE_SYSTEM_NAME_W SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0006)
+#define SCARD_ATTR_SUPRESS_T1_IFS_REQUEST SCARD_ATTR_VALUE(SCARD_CLASS_SYSTEM, 0x0007) /**< FIXME */
+
+#ifdef UNICODE
+#define SCARD_ATTR_DEVICE_FRIENDLY_NAME SCARD_ATTR_DEVICE_FRIENDLY_NAME_W /**< Reader's display name. */
+#define SCARD_ATTR_DEVICE_SYSTEM_NAME SCARD_ATTR_DEVICE_SYSTEM_NAME_W /**< Reader's system name. */
+#else
+#define SCARD_ATTR_DEVICE_FRIENDLY_NAME SCARD_ATTR_DEVICE_FRIENDLY_NAME_A /**< Reader's display name. */
+#define SCARD_ATTR_DEVICE_SYSTEM_NAME SCARD_ATTR_DEVICE_SYSTEM_NAME_A /**< Reader's system name. */
+#endif
+
+/**
+ * Provide source compatibility on different platforms
+ */
+#define SCARD_CTL_CODE(code) (0x42000000 + (code))
+
+/**
+ * PC/SC part 10 v2.02.07 March 2010 reader tags
+ */
+#define CM_IOCTL_GET_FEATURE_REQUEST SCARD_CTL_CODE(3400)
+
+#define FEATURE_VERIFY_PIN_START 0x01
+#define FEATURE_VERIFY_PIN_FINISH 0x02
+#define FEATURE_MODIFY_PIN_START 0x03
+#define FEATURE_MODIFY_PIN_FINISH 0x04
+#define FEATURE_GET_KEY_PRESSED 0x05
+#define FEATURE_VERIFY_PIN_DIRECT 0x06 /**< Verify PIN */
+#define FEATURE_MODIFY_PIN_DIRECT 0x07 /**< Modify PIN */
+#define FEATURE_MCT_READER_DIRECT 0x08
+#define FEATURE_MCT_UNIVERSAL 0x09
+#define FEATURE_IFD_PIN_PROPERTIES 0x0A /**< retrieve properties of the IFD regarding PIN handling */
+#define FEATURE_ABORT 0x0B
+#define FEATURE_SET_SPE_MESSAGE 0x0C
+#define FEATURE_VERIFY_PIN_DIRECT_APP_ID 0x0D
+#define FEATURE_MODIFY_PIN_DIRECT_APP_ID 0x0E
+#define FEATURE_WRITE_DISPLAY 0x0F
+#define FEATURE_GET_KEY 0x10
+#define FEATURE_IFD_DISPLAY_PROPERTIES 0x11
+#define FEATURE_GET_TLV_PROPERTIES 0x12
+#define FEATURE_CCID_ESC_COMMAND 0x13
+#define FEATURE_EXECUTE_PACE 0x20
+
+/* structures used (but not defined) in PC/SC Part 10:
+ * "IFDs with Secure Pin Entry Capabilities" */
+
+#ifdef UEFI_DRIVER
+#ifndef uint8_t
+#define uint8_t UINT8
+#endif
+#define uint16_t UINT16
+#define uint32_t UINT32
+#define ULONG unsigned long
+#else
+#include <inttypes.h>
+#endif
+
+/* Set structure elements aligment on bytes
+ * http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html */
+#if defined(__APPLE__) | defined(sun)
+#pragma pack(1)
+#else
+#pragma pack(push, 1)
+#endif
+
+/** the structure must be 6-bytes long */
+typedef struct
+{
+ uint8_t tag;
+ uint8_t length;
+ uint32_t value; /**< This value is always in BIG ENDIAN format as documented in PCSC v2 part 10 ch 2.2 page 2. You can use ntohl() for example */
+} PCSC_TLV_STRUCTURE;
+
+/** Since CCID 1.4.1 (revision 5252) the byte order is no more important
+ * These macros are now deprecated and should be removed in the future */
+#define HOST_TO_CCID_16(x) (x)
+#define HOST_TO_CCID_32(x) (x)
+
+/** structure used with \ref FEATURE_VERIFY_PIN_DIRECT */
+typedef struct
+{
+ uint8_t bTimerOut; /**< timeout is seconds (00 means use default timeout) */
+ uint8_t bTimerOut2; /**< timeout in seconds after first key stroke */
+ uint8_t bmFormatString; /**< formatting options */
+ uint8_t bmPINBlockString; /**< bits 7-4 bit size of PIN length in APDU,
+ * bits 3-0 PIN block size in bytes after
+ * justification and formatting */
+ uint8_t bmPINLengthFormat; /**< bits 7-5 RFU,
+ * bit 4 set if system units are bytes, clear if
+ * system units are bits,
+ * bits 3-0 PIN length position in system units */
+ uint16_t wPINMaxExtraDigit; /**< 0xXXYY where XX is minimum PIN size in digits,
+ and YY is maximum PIN size in digits */
+ uint8_t bEntryValidationCondition; /**< Conditions under which PIN entry should
+ * be considered complete */
+ uint8_t bNumberMessage; /**< Number of messages to display for PIN verification */
+ uint16_t wLangId; /**< Language for messages */
+ uint8_t bMsgIndex; /**< Message index (should be 00) */
+ uint8_t bTeoPrologue[3]; /**< T=1 block prologue field to use (fill with 00) */
+ uint32_t ulDataLength; /**< length of Data to be sent to the ICC */
+ uint8_t abData
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+ [] /* valid C99 code */
+#else
+ [0] /* non-standard, but usually working code */
+#endif
+ ; /**< Data to send to the ICC */
+} PIN_VERIFY_STRUCTURE;
+
+/** structure used with \ref FEATURE_MODIFY_PIN_DIRECT */
+typedef struct
+{
+ uint8_t bTimerOut; /**< timeout is seconds (00 means use default timeout) */
+ uint8_t bTimerOut2; /**< timeout in seconds after first key stroke */
+ uint8_t bmFormatString; /**< formatting options */
+ uint8_t bmPINBlockString; /**< bits 7-4 bit size of PIN length in APDU,
+ * bits 3-0 PIN block size in bytes after
+ * justification and formatting */
+ uint8_t bmPINLengthFormat; /**< bits 7-5 RFU,
+ * bit 4 set if system units are bytes, clear if
+ * system units are bits,
+ * bits 3-0 PIN length position in system units */
+ uint8_t bInsertionOffsetOld; /**< Insertion position offset in bytes for
+ the current PIN */
+ uint8_t bInsertionOffsetNew; /**< Insertion position offset in bytes for
+ the new PIN */
+ uint16_t wPINMaxExtraDigit;
+ /**< 0xXXYY where XX is minimum PIN size in digits,
+ and YY is maximum PIN size in digits */
+ uint8_t bConfirmPIN; /**< Flags governing need for confirmation of new PIN */
+ uint8_t bEntryValidationCondition; /**< Conditions under which PIN entry should
+ * be considered complete */
+ uint8_t bNumberMessage; /**< Number of messages to display for PIN verification*/
+ uint16_t wLangId; /**< Language for messages */
+ uint8_t bMsgIndex1; /**< index of 1st prompting message */
+ uint8_t bMsgIndex2; /**< index of 2d prompting message */
+ uint8_t bMsgIndex3; /**< index of 3d prompting message */
+ uint8_t bTeoPrologue[3]; /**< T=1 block prologue field to use (fill with 00) */
+ uint32_t ulDataLength; /**< length of Data to be sent to the ICC */
+ uint8_t abData
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+ [] /* valid C99 code */
+#else
+ [0] /* non-standard, but usually working code */
+#endif
+ ; /**< Data to send to the ICC */
+} PIN_MODIFY_STRUCTURE;
+
+/** structure used with \ref FEATURE_IFD_PIN_PROPERTIES */
+typedef struct {
+ uint16_t wLcdLayout; /**< display characteristics */
+ uint8_t bEntryValidationCondition;
+ uint8_t bTimeOut2;
+} PIN_PROPERTIES_STRUCTURE;
+
+/* restore default structure elements alignment */
+#if defined(__APPLE__) | defined(sun)
+#pragma pack()
+#else
+#pragma pack(pop)
+#endif
+
+/* properties returned by FEATURE_GET_TLV_PROPERTIES */
+#define PCSCv2_PART10_PROPERTY_wLcdLayout 1
+#define PCSCv2_PART10_PROPERTY_bEntryValidationCondition 2
+#define PCSCv2_PART10_PROPERTY_bTimeOut2 3
+#define PCSCv2_PART10_PROPERTY_wLcdMaxCharacters 4
+#define PCSCv2_PART10_PROPERTY_wLcdMaxLines 5
+#define PCSCv2_PART10_PROPERTY_bMinPINSize 6
+#define PCSCv2_PART10_PROPERTY_bMaxPINSize 7
+#define PCSCv2_PART10_PROPERTY_sFirmwareID 8
+#define PCSCv2_PART10_PROPERTY_bPPDUSupport 9
+#define PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize 10
+#define PCSCv2_PART10_PROPERTY_wIdVendor 11
+#define PCSCv2_PART10_PROPERTY_wIdProduct 12
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/wintypes.h b/MdeModulePkg/Library/SmartCardReader/wintypes.h
new file mode 100644
index 0000000..565dbb8
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/wintypes.h
@@ -0,0 +1,120 @@
+/*
+ * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
+ *
+ * Copyright (C) 1999
+ * David Corcoran <***@musclecard.com>
+ * Copyright (C) 2002-2011
+ * Ludovic Rousseau <***@free.fr>
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+Changes to this license can be made only by the copyright author with
+explicit written consent.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: wintypes.h 6851 2014-02-14 15:43:32Z rousseau $
+ */
+
+/**
+ * @file
+ * @brief This keeps a list of Windows(R) types.
+ */
+
+#ifndef __wintypes_h__
+#define __wintypes_h__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef __APPLE__
+
+#include <stdint.h>
+
+#ifndef BYTE
+ typedef uint8_t BYTE;
+#endif
+ typedef uint8_t UCHAR;
+ typedef UCHAR *PUCHAR;
+ typedef uint16_t USHORT;
+
+#ifndef __COREFOUNDATION_CFPLUGINCOM__
+ typedef uint32_t ULONG;
+ typedef void *LPVOID;
+ typedef int16_t BOOL;
+#endif
+
+ typedef ULONG *PULONG;
+ typedef const void *LPCVOID;
+ typedef uint32_t DWORD;
+ typedef DWORD *PDWORD;
+ typedef uint16_t WORD;
+ typedef int32_t LONG;
+ typedef const char *LPCSTR;
+ typedef const BYTE *LPCBYTE;
+ typedef BYTE *LPBYTE;
+ typedef DWORD *LPDWORD;
+ typedef char *LPSTR;
+
+#else
+
+#ifndef BYTE
+ typedef unsigned char BYTE;
+#endif
+ typedef unsigned char UCHAR;
+ typedef UCHAR *PUCHAR;
+ typedef unsigned short USHORT;
+
+#ifndef __COREFOUNDATION_CFPLUGINCOM__
+ typedef unsigned long ULONG;
+ typedef void *LPVOID;
+#endif
+
+ typedef const void *LPCVOID;
+ typedef unsigned long DWORD;
+ typedef DWORD *PDWORD;
+ typedef long LONG;
+ typedef const char *LPCSTR;
+ typedef const BYTE *LPCBYTE;
+ typedef BYTE *LPBYTE;
+ typedef DWORD *LPDWORD;
+ typedef char *LPSTR;
+
+ /* these types were deprecated but still used by old drivers and
+ * applications. So just declare and use them. */
+ typedef LPSTR LPTSTR;
+ typedef LPCSTR LPCTSTR;
+
+ /* types unused by pcsc-lite */
+ typedef short BOOL;
+ typedef unsigned short WORD;
+ typedef ULONG *PULONG;
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--
2.1.4


------------------------------------------------------------------------------
Ludovic Rousseau
2015-06-10 18:27:42 UTC
Permalink
Add SmartCardReader specific files. These files have been written
specifically for UEFI.

This provides an implementation of the "Smart Card Reader Protocol" or
EFI_SMART_CARD_READER_PROTOCOL as described in "Unified Extensible
Firmware Interface Specification", version 2.5, April 2015, chapter
"35.6.1 Smart Card Reader Protocol".

The code heavily reuse an existing CCID driver from the CCID project
http://pcsclite.alioth.debian.org/ccid.html

CCID and ICCD are a protocols defined by the USB working group. All
modern USB smart card readers use CCID (or its variation ICCD for tokens).

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ludovic Rousseau <***@gmail.com>
---
MdeModulePkg/Library/SmartCardReader/CcidDriver.c | 819 +++++++++++++++++++++
MdeModulePkg/Library/SmartCardReader/CcidDriver.h | 154 ++++
.../Library/SmartCardReader/ComponentName.c | 198 +++++
.../Library/SmartCardReader/ComponentName.h | 128 ++++
.../Library/SmartCardReader/DriverBinding.h | 211 ++++++
MdeModulePkg/Library/SmartCardReader/License.txt | 87 +++
.../Library/SmartCardReader/SmartCardReader.inf | 97 +++
.../Library/SmartCardReader/SmartCardReader_impl.c | 453 ++++++++++++
.../Library/SmartCardReader/SmartCardReader_impl.h | 94 +++
MdeModulePkg/Library/SmartCardReader/config.h | 64 ++
MdeModulePkg/Library/SmartCardReader/debug.c | 62 ++
MdeModulePkg/Library/SmartCardReader/debuglog.h | 81 ++
12 files changed, 2448 insertions(+)
create mode 100644 MdeModulePkg/Library/SmartCardReader/CcidDriver.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/CcidDriver.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/ComponentName.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/ComponentName.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/DriverBinding.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/License.txt
create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader.inf
create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/config.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/debug.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/debuglog.h

diff --git a/MdeModulePkg/Library/SmartCardReader/CcidDriver.c b/MdeModulePkg/Library/SmartCardReader/CcidDriver.c
new file mode 100644
index 0000000..9c60211
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/CcidDriver.c
@@ -0,0 +1,819 @@
+/*
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** @file
+ Entry points for the UEFI CCID driver
+
+ When a USB CCID device is inserted or removed then Start or Stop
+ functions from this file are called.
+
+**/
+
+#include <Library/PrintLib.h>
+#include <Protocol/SmartCardReader.h>
+
+#include "CcidDriver.h"
+#include "SmartCardReader_impl.h"
+
+#include "ifdhandler.h"
+#include "debuglog.h"
+#include "defs.h"
+#include "utils.h"
+#include "ccid_ifdhandler.h"
+#include "ccid.h"
+#include "ccid_uefi.h"
+
+static int Lun = 0;
+
+///
+/// Driver Binding Protocol instance
+///
+EFI_DRIVER_BINDING_PROTOCOL gSmartCardReaderDriverBinding = {
+ SmartCardReaderDriverBindingSupported,
+ SmartCardReaderDriverBindingStart,
+ SmartCardReaderDriverBindingStop,
+ CCID_DRIVER_VERSION,
+ NULL,
+ NULL
+};
+
+
+/**
+ Unloads an image.
+
+ @param ImageHandle Handle that identifies the image to be unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+
+ Log0(PCSC_LOG_DEBUG);
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Retrieve array of all handles in the handle database
+ //
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ Log2(PCSC_LOG_DEBUG, "LocateHandleBuffer %d", Status);
+ return Status;
+ }
+
+ //
+ // Disconnect the current driver from handles in the handle database
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
+ }
+
+ //
+ // Free the array of handles
+ //
+ FreePool (HandleBuffer);
+
+ //
+ // Uninstall protocols installed in the driver entry point
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid, &gSmartCardReaderDriverBinding,
+ &gEfiComponentNameProtocolGuid, &gSmartCardReaderComponentName,
+ &gEfiComponentName2ProtocolGuid, &gSmartCardReaderComponentName2,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ Log2(PCSC_LOG_DEBUG, "UninstallMultipleProtocolInterfaces %d", Status);
+ return Status;
+ }
+
+
+ //
+ // Do any additional cleanup that is required for this driver
+ //
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This is the declaration of an EFI image entry point. This entry point is
+ the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
+ both device drivers and bus drivers.
+
+ @param ImageHandle The firmware allocated handle for the UEFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval Others An unexpected error occurred.
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ // Install UEFI Driver Model protocol(s).
+ //
+ Status = EfiLibInstallAllDriverProtocols2 (
+ ImageHandle,
+ SystemTable,
+ &gSmartCardReaderDriverBinding,
+ ImageHandle,
+ &gSmartCardReaderComponentName,
+ &gSmartCardReaderComponentName2,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+
+/**
+ Tests to see if this driver supports a given controller. If a child
+ device is provided, it further tests to see if this driver supports
+ creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports
+ the device specified by ControllerHandle. Drivers will typically use
+ the device path attached to ControllerHandle and/or the services from
+ the bus I/O abstraction attached to ControllerHandle to determine if
+ the driver supports ControllerHandle. This function may be called many
+ times during platform initialization. In order to reduce boot times,
+ the tests performed by this function must be very small, and take as
+ little time as possible to execute. This function must not change the
+ state of any hardware devices, and this function must be aware that
+ the device specified by ControllerHandle may already be managed by the
+ same driver or a different driver. This function must match its calls
+ to AllocatePages() with FreePages(), AllocatePool() with FreePool(),
+ and OpenProtocol() with CloseProtocol(). Because ControllerHandle may
+ have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with
+ CloseProtocol(). This is required to guarantee the state of
+ ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the
+ EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test.
+ This handle must support a protocol
+ interface that supplies an I/O
+ abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of
+ a device path. This parameter is
+ ignored by device drivers, and is
+ optional for bus drivers. For bus
+ drivers, if this parameter is not
+ NULL, then the bus driver must
+ determine if the bus controller
+ specified by ControllerHandle and the
+ child controller specified by
+ RemainingDevicePath are both
+ supported by this bus driver.
+
+ @retval EFI_SUCCESS The device specified by
+ ControllerHandle and
+ RemainingDevicePath is supported by
+ the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by
+ ControllerHandle and
+ RemainingDevicePath is already being
+ managed by the driver specified by
+ This.
+ @retval EFI_ACCESS_DENIED The device specified by
+ ControllerHandle and
+ RemainingDevicePath is already being
+ managed by a different driver or an
+ application that requires exclusive
+ access. Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by
+ ControllerHandle and
+ RemainingDevicePath is not supported
+ by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Use the USB I/O Protocol interface to check whether Controller is
+ // a CCID device that can be managed by this driver.
+ //
+ Status = EFI_UNSUPPORTED;
+ if (IsUsbCcid (UsbIo)) {
+ Status = EFI_SUCCESS;
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
+
+/**
+ Initialize the USB CCID device.
+
+ @param UsbCcidDev Device instance to be initialized.
+
+ @retval EFI_SUCCESS USB CCID device successfully initialized..
+ @retval Other USB CCID device was not initialized
+ successfully.
+
+**/
+EFI_STATUS
+FinalizeUsbCcidDevice (
+ IN OUT USB_CCID_DEV *UsbCcidDev
+ )
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ Log0(PCSC_LOG_DEBUG);
+
+ if (IFD_SUCCESS != IFDHCloseChannel(UsbCcidDev->Lun)) {
+ status = EFI_UNSUPPORTED;
+ }
+
+ return status;
+}
+
+/**
+ Initialize the USB CCID device.
+
+ @param UsbCcidDev Device instance to be initialized.
+
+ @retval EFI_SUCCESS USB CCID device successfully initialized..
+ @retval Other USB CCID device was not initialized
+ successfully.
+
+**/
+EFI_STATUS
+InitializeUsbCcidDevice (
+ IN OUT USB_CCID_DEV *UsbCcidDevice
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_STATUS Status;
+ CHAR16 *ManufacturerString = NULL;
+ CHAR16 *ProductString = NULL;
+ UINT16 *LangIDTable;
+ UINT16 TableSize;
+ INTN Index;
+ CHAR16 TxtLun[10];
+ INTN reader_index;
+ CcidDesc *ccid_slot;
+
+ Log0(PCSC_LOG_DEBUG);
+
+ if (IFD_SUCCESS != IFDHCreateChannel(Lun, (DWORD)UsbCcidDevice)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ UsbCcidDevice->Lun = Lun;
+ UsbCcidDevice->State = SCARD_UNKNOWN;
+ UsbCcidDevice->AtrLength = 0;
+ UsbCcidDevice->InUse = 0;
+ UsbCcidDevice->CardProtocol = -1;
+
+ /* Lun are not recycled */
+ Lun++;
+
+ UsbIo = UsbCcidDevice->UsbIo;
+
+ //
+ // Get all supported languages.
+ //
+ TableSize = 0;
+ LangIDTable = NULL;
+ Status = UsbIo->UsbGetSupportedLanguages(UsbIo, &LangIDTable, &TableSize);
+ if (EFI_ERROR(Status)) {
+ Log1(PCSC_LOG_ERROR, "UsbGetSupportedLanguages");
+ goto error;
+ }
+
+ /* Get Manufacturer string */
+ for (Index = 0; Index < TableSize / sizeof (LangIDTable[0]); Index++) {
+ ManufacturerString = NULL;
+ Status = UsbIo->UsbGetStringDescriptor(UsbIo,
+ LangIDTable[Index],
+ UsbCcidDevice->DeviceDescriptor.StrManufacturer,
+ &ManufacturerString);
+
+ if (EFI_ERROR (Status) || (ManufacturerString == NULL)) {
+ continue;
+ }
+
+ StrCpy(UsbCcidDevice->ReaderName, ManufacturerString);
+ StrCat(UsbCcidDevice->ReaderName, L" ");
+
+ FreePool(ManufacturerString);
+ break;
+ }
+
+ /* Get Product string */
+ for (Index = 0; Index < TableSize / sizeof (LangIDTable[0]); Index++) {
+ ProductString = NULL;
+ Status = UsbIo->UsbGetStringDescriptor(UsbIo,
+ LangIDTable[Index],
+ UsbCcidDevice->DeviceDescriptor.StrProduct,
+ &ProductString);
+
+ if (EFI_ERROR (Status) || (ProductString == NULL)) {
+ continue;
+ }
+
+ StrCat(UsbCcidDevice->ReaderName, ProductString);
+
+ FreePool(ProductString);
+ break;
+ }
+
+error:
+ /* Can't get the strings from the device */
+ if ((NULL == ManufacturerString) || (NULL == ProductString)) {
+ UnicodeSPrint(UsbCcidDevice->ReaderName,
+ sizeof(UsbCcidDevice->ReaderName)/sizeof(UsbCcidDevice->ReaderName[0]),
+ L"%04X:%04X",
+ UsbCcidDevice->DeviceDescriptor.IdVendor,
+ UsbCcidDevice->DeviceDescriptor.IdProduct);
+ }
+
+ /* Add the Lun */
+ UnicodeSPrint(TxtLun, sizeof(TxtLun)/sizeof(TxtLun[0]), L" %d", UsbCcidDevice->Lun);
+ StrCat(UsbCcidDevice->ReaderName, TxtLun);
+
+ /* Length (in bytes) including Null terminator */
+ UsbCcidDevice->ReaderNameLength = StrSize(UsbCcidDevice->ReaderName);
+
+ /* set the reader name to the lower level */
+ reader_index = LunToReaderIndex(UsbCcidDevice->Lun);
+ ccid_slot = get_ccid_slot(reader_index);
+ ccid_slot->readerName = UsbCcidDevice->ReaderName;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot
+ service ConnectController().
+
+ As a result, much of the error checking on the parameters to Start()
+ has been moved into this common boot service. It is legal to call
+ Start() from other locations, but the following calling restrictions
+ must be followed, or the system behavior will not be deterministic.
+
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
+ naturally aligned EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver
+ specified by This must have been called with the same calling
+ parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the
+ EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to
+ start. This handle must support a
+ protocol interface that supplies an
+ I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of
+ a device path. This parameter is
+ ignored by device drivers, and is
+ optional for bus drivers. For a bus
+ driver, if this parameter is NULL,
+ then handles for all the children of
+ Controller are created by this
+ driver. If this parameter is not
+ NULL and the first Device Path Node
+ is not the End of Device Path Node,
+ then only the handle for the child
+ device specified by the first Device
+ Path Node of RemainingDevicePath is
+ created by this driver. If the first
+ Device Path Node of
+ RemainingDevicePath is the End of
+ Device Path Node, no child handle is
+ created by this driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to
+ a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to
+ a lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ USB_CCID_DEV *UsbCcidDevice;
+ EFI_TPL OldTpl;
+ EFI_SMART_CARD_READER_PROTOCOL SmartCardReaderProtocol = {
+ .SCardConnect = SCardConnect,
+ .SCardDisconnect = SCardDisconnect,
+ .SCardStatus = SCardStatus,
+ .SCardTransmit =SCardTransmit,
+ .SCardControl = SCardControl,
+ .SCardGetAttrib = SCardGetAttrib
+ };
+ INTN slot, reader_index;
+ CcidDesc *ccid_slot;
+ _ccid_descriptor *ccid_descriptor;
+ USB_CCID_DEV *previous_UsbCcidDevice;
+
+ Log0(PCSC_LOG_DEBUG);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Open USB I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ Log2(PCSC_LOG_DEBUG, "OpenProtocol %d", Status);
+ goto ErrorExit1;
+ }
+
+ UsbCcidDevice = AllocateZeroPool (sizeof (USB_CCID_DEV));
+ ASSERT (UsbCcidDevice != NULL);
+
+ UsbCcidDevice->UsbIo = UsbIo;
+ UsbCcidDevice->Signature = USB_CCID_DEV_SIGNATURE;
+ UsbCcidDevice->ControllerHandle = ControllerHandle;
+ UsbCcidDevice->DriverBindingHandle = This->DriverBindingHandle;
+
+ Status = InitializeUsbCcidDevice(UsbCcidDevice);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ /* set the protocol functions */
+ UsbCcidDevice->SmartCardReaderProtocol = SmartCardReaderProtocol;
+
+ Status = gBS->InstallProtocolInterface (
+ &ControllerHandle,
+ &gEfiSmartCardReaderProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &UsbCcidDevice->SmartCardReaderProtocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ Log2(PCSC_LOG_DEBUG, "InstallProtocolInterface %d", Status);
+ goto ErrorExit;
+ }
+
+ UsbCcidDevice->ControllerNameTable = NULL;
+ AddUnicodeString2 (
+ "eng",
+ gSmartCardReaderComponentName.SupportedLanguages,
+ &UsbCcidDevice->ControllerNameTable,
+ L"Generic CCID Reader",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gSmartCardReaderComponentName2.SupportedLanguages,
+ &UsbCcidDevice->ControllerNameTable,
+ L"Generic CCID Reader",
+ FALSE
+ );
+
+ /* multi slot readers */
+ reader_index = LunToReaderIndex(UsbCcidDevice->Lun);
+ ccid_slot = get_ccid_slot(reader_index);
+ ccid_descriptor = get_ccid_descriptor(reader_index);
+ previous_UsbCcidDevice = UsbCcidDevice;
+
+ for (slot=1; slot <= ccid_descriptor->bMaxSlotIndex; slot++) {
+ USB_CCID_DEV *new_UsbCcidDevice;
+ EFI_HANDLE new_ControllerHandle = NULL;
+ int new_reader_index;
+ CHAR16 TxtSlot[10];
+
+ Log2(PCSC_LOG_DEBUG, "slot: %d", slot);
+
+ if (-1 == (new_reader_index = GetNewReaderIndex(Lun))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ new_UsbCcidDevice = AllocateZeroPool (sizeof (USB_CCID_DEV));
+ ASSERT (new_UsbCcidDevice != NULL);
+
+ /* Copy the USB device */
+ duplicate_usb_device(reader_index, new_reader_index);
+
+ /* copy the UEFI device */
+ *new_UsbCcidDevice = *UsbCcidDevice;
+ new_UsbCcidDevice->Lun = Lun;
+ new_UsbCcidDevice->SlotNumber = slot;
+
+ /* Add the slot number */
+ UnicodeSPrint(TxtSlot, sizeof(TxtSlot)/sizeof(TxtSlot[0]), L", %d", slot);
+ StrCat(new_UsbCcidDevice->ReaderName, TxtSlot);
+
+ /* Set the reader name to the lower level */
+ new_reader_index = LunToReaderIndex(new_UsbCcidDevice->Lun);
+ get_ccid_slot(new_reader_index)->readerName = new_UsbCcidDevice->ReaderName;
+
+ /* Set the slot number ta the lower level */
+ get_ccid_descriptor(new_reader_index)->bCurrentSlotIndex = slot;
+
+ /* New Lun for a new slot */
+ Lun++;
+
+ /* Chaining */
+ previous_UsbCcidDevice->NextSlot = new_UsbCcidDevice;
+ previous_UsbCcidDevice = new_UsbCcidDevice;
+
+ /* Create a new UEFI SmartCardReaderProtocol object */
+ Status = gBS->InstallProtocolInterface (
+ &new_ControllerHandle,
+ &gEfiSmartCardReaderProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &new_UsbCcidDevice->SmartCardReaderProtocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ Log2(PCSC_LOG_DEBUG, "InstallProtocolInterface %d", Status);
+ goto ErrorExit;
+ }
+
+ new_UsbCcidDevice->ControllerHandle = new_ControllerHandle;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+ //
+ // Error handler
+ //
+ErrorExit:
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ FreePool (UsbCcidDevice);
+ UsbCcidDevice = NULL;
+ }
+
+ErrorExit1:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot
+ service DisconnectController().
+
+ As a result, much of the error checking on the parameters to Stop()
+ has been moved into this common boot service. It is legal to call
+ Stop() from other locations, but the following calling restrictions
+ must be followed, or the system behavior will not be deterministic.
+
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a
+ previous call to this same driver's Start() function.
+
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be
+ a valid EFI_HANDLE. In addition, all of these handles must have
+ been created in this driver's Start() function, and the Start()
+ function must have called OpenProtocol() on ControllerHandle with
+ an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the
+ EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped.
+ The handle must support a bus specific
+ I/O protocol for the driver to use to
+ stop the device.
+ @param[in] NumberOfChildren The number of child device handles in
+ ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed.
+ May be NULL if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a
+ device error.
+
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ USB_CCID_DEV *UsbCcidDevice;
+ EFI_SMART_CARD_READER_PROTOCOL *SmartCardReaderProtocol;
+
+ Log0(PCSC_LOG_DEBUG);
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSmartCardReaderProtocolGuid,
+ (VOID **) &SmartCardReaderProtocol,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ UsbCcidDevice = USB_CCID_DEV_FROM_SMART_CARD_READER_PROTOCOL (SmartCardReaderProtocol);
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ //
+ // Free all resources.
+ //
+ if (UsbCcidDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (UsbCcidDevice->ControllerNameTable);
+ }
+
+ /* For each slot */
+ while (UsbCcidDevice) {
+ USB_CCID_DEV *NextSlot;
+
+ Log2(PCSC_LOG_DEBUG, "Closing slot: %d", UsbCcidDevice->SlotNumber);
+
+ Status = FinalizeUsbCcidDevice(UsbCcidDevice);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ /* Remove the protocol Interface */
+ Status = gBS->UninstallProtocolInterface (
+ UsbCcidDevice->ControllerHandle,
+ &gEfiSmartCardReaderProtocolGuid,
+ &UsbCcidDevice->SmartCardReaderProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ NextSlot = UsbCcidDevice->NextSlot;
+
+ /* Free allocated memory */
+ FreePool (UsbCcidDevice);
+
+ UsbCcidDevice = NextSlot;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Uses USB I/O to check whether the device is a USB CCID device.
+
+ @param UsbIo Pointer to a USB I/O protocol instance.
+
+ @retval TRUE Device is a USB CCID device.
+ @retval FALSE Device is a not USB CCID device.
+
+ **/
+BOOLEAN
+IsUsbCcid (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+
+ //
+ // Get the default interface descriptor
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (
+ UsbIo,
+ &InterfaceDescriptor
+ );
+
+ if (EFI_ERROR (Status)) {
+ Log2(PCSC_LOG_DEBUG, "UsbGetInterfaceDescriptor %d", Status);
+ return FALSE;
+ }
+
+ Status = UsbIo->UsbGetDeviceDescriptor (
+ UsbIo,
+ &DeviceDescriptor);
+
+ if (EFI_ERROR (Status)) {
+ Log2(PCSC_LOG_DEBUG, "UsbGetDeviceDescriptor %d", Status);
+ return FALSE;
+ }
+
+ Log3(PCSC_LOG_DEBUG, "IdVendor: %04X, IdProduct: %04X",
+ DeviceDescriptor.IdVendor, DeviceDescriptor.IdProduct);
+
+ if (InterfaceDescriptor.InterfaceClass == CLASS_CCID) {
+ Log1(PCSC_LOG_DEBUG, "Found a CCID device!");
+
+ return TRUE;
+ }
+
+ /* Log1(PCSC_LOG_DEBUG, "Not a CCID device"); */
+ return FALSE;
+}
+
diff --git a/MdeModulePkg/Library/SmartCardReader/CcidDriver.h b/MdeModulePkg/Library/SmartCardReader/CcidDriver.h
new file mode 100644
index 0000000..14fade4
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/CcidDriver.h
@@ -0,0 +1,154 @@
+/*
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** @file
+ TODO: Brief Description of UEFI Driver SmartCardReader
+
+ TODO: Detailed Description of UEFI Driver SmartCardReader
+
+**/
+
+#ifndef __EFI_CCID_DRIVER_H__
+#define __EFI_CCID_DRIVER_H__
+
+#include <Uefi.h>
+
+//
+// Libraries
+//
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+
+//
+// UEFI Driver Model Protocols
+//
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/SmartCardReader.h>
+
+//
+// Consumed Protocols
+//
+#include <Protocol/UsbIo.h>
+
+
+//
+// Produced Protocols
+//
+
+
+//
+// Guids
+//
+
+//
+// Driver Version
+//
+#define CCID_DRIVER_VERSION 0x00000001
+
+#ifndef MAX_ATR_SIZE
+#define MAX_ATR_SIZE 33 /* from pcsclite.h */
+#endif
+
+//
+// Protocol instances
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gSmartCardReaderDriverBinding;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSmartCardReaderComponentName2;
+extern EFI_COMPONENT_NAME_PROTOCOL gSmartCardReaderComponentName;
+
+
+//
+// Include files with function prototypes
+//
+#include "DriverBinding.h"
+#include "ComponentName.h"
+
+#define CLASS_CCID 11
+
+#define USB_CCID_DEV_SIGNATURE SIGNATURE_32 ('c', 'c', 'i', 'd')
+
+
+///
+/// Device instance of USB CCID device.
+///
+typedef struct _USB_CCID_DEV {
+ UINTN Signature;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_EVENT DelayedRecoveryEvent;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_HANDLE *ControllerHandle;
+ EFI_HANDLE *DriverBindingHandle;
+ EFI_SMART_CARD_READER_PROTOCOL SmartCardReaderProtocol;
+ EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+ EFI_USB_CONFIG_DESCRIPTOR ConfigDescriptor;
+ EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ INTN SlotNumber;
+ struct _USB_CCID_DEV *NextSlot;
+ UINTN Lun;
+ CHAR16 ReaderName[128];
+ INTN ReaderNameLength;
+ unsigned char Atr[MAX_ATR_SIZE];
+ INTN AtrLength;
+ INTN CardProtocol;
+ INTN State;
+ INTN InUse;
+} USB_CCID_DEV;
+
+#define USB_CCID_DEV_FROM_SMART_CARD_READER_PROTOCOL(a) \
+ CR(a, USB_CCID_DEV, SmartCardReaderProtocol, USB_CCID_DEV_SIGNATURE)
+
+
+//
+// Internal worker functions
+//
+
+/**
+ Uses USB I/O to check whether the device is a USB CCID device.
+
+ @param UsbIo Pointer to a USB I/O protocol instance.
+
+ @retval TRUE Device is a USB CCID device.
+ @retval FALSE Device is a not USB CCID device.
+
+**/
+BOOLEAN
+IsUsbCcid (
+ IN EFI_USB_IO_PROTOCOL *UsbIo
+ );
+
+#endif
diff --git a/MdeModulePkg/Library/SmartCardReader/ComponentName.c b/MdeModulePkg/Library/SmartCardReader/ComponentName.c
new file mode 100644
index 0000000..3927361
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/ComponentName.c
@@ -0,0 +1,198 @@
+/*
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+/** @file
+ TODO: Brief Description of UEFI Driver SmartCardReader
+
+ TODO: Detailed Description of UEFI Driver SmartCardReader
+
+**/
+
+#include "CcidDriver.h"
+
+///
+/// Component Name Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME_PROTOCOL gSmartCardReaderComponentName = {
+ (EFI_COMPONENT_NAME_GET_DRIVER_NAME) SmartCardReaderComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)SmartCardReaderComponentNameGetControllerName,
+ "eng"
+};
+
+///
+/// Component Name 2 Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME2_PROTOCOL gSmartCardReaderComponentName2 = {
+ SmartCardReaderComponentNameGetDriverName,
+ SmartCardReaderComponentNameGetControllerName,
+ "en"
+};
+
+///
+/// Table of driver names
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_UNICODE_STRING_TABLE mSmartCardReaderDriverNameTable[] = {
+ { "eng;en", (CHAR16 *)L"USB Smart Card Driver (CCID)" },
+ { NULL, NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three-character ISO 639-2 language
+ identifier. This is the language of the driver
+ name that that the caller is requesting, and it
+ must match one of the languages specified in
+ SupportedLanguages. The number of languages
+ supported by a driver is up to the driver writer.
+ @param DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the driver
+ specified by This in the language specified by
+ Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver
+ specified by This and the language
+ specified by Language was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not
+ support the language specified by
+ Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSmartCardReaderDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This != &gSmartCardReaderComponentName2)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL
+ instance.
+ @param ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+ @param ChildHandle The handle of the child controller to
+ retrieve the name of. This is an optional
+ parameter that may be NULL. It will be NULL
+ for device drivers. It will also be NULL for
+ a bus drivers that wish to retrieve the name
+ of the bus controller. It will not be NULL
+ for a bus driver that wishes to retrieve the
+ name of a child controller.
+ @param Language A pointer to a three character ISO 639-2
+ language identifier. This is the language of
+ the controller name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages.
+ The number of languages supported by a driver
+ is up to the driver writer.
+ @param ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language, from the point of view of the
+ driver specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user-readable
+ name in the language specified by
+ Language for the driver specified by
+ This was returned in DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not
+ a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not
+ currently managing the controller
+ specified by ControllerHandle and
+ ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not
+ support the language specified by
+ Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // ChildHandle must be NULL for a Device Driver
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gSmartCardReaderDriverBinding.DriverBindingHandle,
+ &gEfiUsbIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Lookup name of controller specified by ControllerHandle
+ //
+ Status = EFI_UNSUPPORTED;
+
+ return Status;
+}
diff --git a/MdeModulePkg/Library/SmartCardReader/ComponentName.h b/MdeModulePkg/Library/SmartCardReader/ComponentName.h
new file mode 100644
index 0000000..5102df5
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/ComponentName.h
@@ -0,0 +1,128 @@
+/*
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** @file
+ TODO: Brief Description of UEFI Driver SmartCardReader
+
+ TODO: Detailed Description of UEFI Driver SmartCardReader
+
+**/
+
+/**
+ Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three-character ISO 639-2 language
+ identifier. This is the language of the driver
+ name that that the caller is requesting, and it
+ must match one of the languages specified in
+ SupportedLanguages. The number of languages
+ supported by a driver is up to the driver writer.
+ @param DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the driver
+ specified by This in the language specified by
+ Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver
+ specified by This and the language
+ specified by Language was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not
+ support the language specified by
+ Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL
+ instance.
+ @param ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+ @param ChildHandle The handle of the child controller to
+ retrieve the name of. This is an optional
+ parameter that may be NULL. It will be NULL
+ for device drivers. It will also be NULL for
+ a bus drivers that wish to retrieve the name
+ of the bus controller. It will not be NULL
+ for a bus driver that wishes to retrieve the
+ name of a child controller.
+ @param Language A pointer to a three character ISO 639-2
+ language identifier. This is the language of
+ the controller name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages.
+ The number of languages supported by a driver
+ is up to the driver writer.
+ @param ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language, from the point of view of the
+ driver specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user-readable
+ name in the language specified by
+ Language for the driver specified by
+ This was returned in DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not
+ a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not
+ currently managing the controller
+ specified by ControllerHandle and
+ ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not
+ support the language specified by
+ Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
diff --git a/MdeModulePkg/Library/SmartCardReader/DriverBinding.h b/MdeModulePkg/Library/SmartCardReader/DriverBinding.h
new file mode 100644
index 0000000..7eb55bd
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/DriverBinding.h
@@ -0,0 +1,211 @@
+/*
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** @file
+ TODO: Brief Description of UEFI Driver SmartCardReader
+
+ TODO: Detailed Description of UEFI Driver SmartCardReader
+
+**/
+
+/**
+ Tests to see if this driver supports a given controller. If a child
+ device is provided, it further tests to see if this driver supports
+ creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports
+ the device specified by ControllerHandle. Drivers will typically use
+ the device path attached to ControllerHandle and/or the services from
+ the bus I/O abstraction attached to ControllerHandle to determine if
+ the driver supports ControllerHandle. This function may be called many
+ times during platform initialization. In order to reduce boot times,
+ the tests performed by this function must be very small, and take as
+ little time as possible to execute. This function must not change the
+ state of any hardware devices, and this function must be aware that
+ the device specified by ControllerHandle may already be managed by the
+ same driver or a different driver. This function must match its calls
+ to AllocatePages() with FreePages(), AllocatePool() with FreePool(),
+ and OpenProtocol() with CloseProtocol(). Because ControllerHandle may
+ have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with
+ CloseProtocol(). This is required to guarantee the state of
+ ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the
+ EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test.
+ This handle must support a protocol
+ interface that supplies an I/O
+ abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of
+ a device path. This parameter is
+ ignored by device drivers, and is
+ optional for bus drivers. For bus
+ drivers, if this parameter is not
+ NULL, then the bus driver must
+ determine if the bus controller
+ specified by ControllerHandle and the
+ child controller specified by
+ RemainingDevicePath are both
+ supported by this bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle
+ and RemainingDevicePath is supported
+ by the driver specified by This.
+
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle
+ and RemainingDevicePath is already
+ being managed by the driver specified
+ by This.
+
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle
+ and RemainingDevicePath is already
+ being managed by a different driver
+ or an application that requires
+ exclusive access. Currently not
+ implemented.
+
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle
+ and RemainingDevicePath is not
+ supported by the driver specified by
+ This.
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot
+ service ConnectController().
+
+ As a result, much of the error checking on the parameters to Start()
+ has been moved into this common boot service. It is legal to call
+ Start() from other locations, but the following calling restrictions
+ must be followed, or the system behavior will not be deterministic.
+
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
+ naturally aligned EFI_DEVICE_PATH_PROTOCOL.
+
+ 3. Prior to calling Start(), the Supported() function for the driver
+ specified by This must have been called with the same calling
+ parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the
+ EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to
+ start. This handle must support a
+ protocol interface that supplies an
+ I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of
+ a device path. This parameter is
+ ignored by device drivers, and is
+ optional for bus drivers. For a bus
+ driver, if this parameter is NULL,
+ then handles for all the children of
+ Controller are created by this
+ driver. If this parameter is not
+ NULL and the first Device Path Node
+ is not the End of Device Path Node,
+ then only the handle for the child
+ device specified by the first Device
+ Path Node of RemainingDevicePath is
+ created by this driver. If the first
+ Device Path Node of
+ RemainingDevicePath is the End of
+ Device Path Node, no child handle is
+ created by this driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to
+ a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to
+ a lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot
+ service DisconnectController().
+
+ As a result, much of the error checking on the parameters to Stop()
+ has been moved into this common boot service. It is legal to call
+ Stop() from other locations, but the following calling restrictions
+ must be followed, or the system behavior will not be deterministic.
+
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a
+ previous call to this same driver's Start() function.
+
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be
+ a valid EFI_HANDLE. In addition, all of these handles must have
+ been created in this driver's Start() function, and the Start()
+ function must have called OpenProtocol() on ControllerHandle with
+ an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the
+ EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped.
+ The handle must support a bus specific
+ I/O protocol for the driver to use to
+ stop the device.
+ @param[in] NumberOfChildren The number of child device handles in
+ ChildHandleBuffer.
+
+ @param[in] ChildHandleBuffer An array of child handles to be freed.
+ May be NULL if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to
+ a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+SmartCardReaderDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
diff --git a/MdeModulePkg/Library/SmartCardReader/License.txt b/MdeModulePkg/Library/SmartCardReader/License.txt
new file mode 100644
index 0000000..328a934
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/License.txt
@@ -0,0 +1,87 @@
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+---
+
+Files reader.h, ifdhandler.h, misc.h, pcsclite.h and wintypes.h are from
+the pcsc-lite project http://pcsclite.alioth.debian.org/pcsclite.html
+and are copyrighted by:
+- Ludovic Rousseau <***@free.fr>
+- David Corcoran <***@musclecard.com>
+- Damien Sauveron <***@labri.fr>
+- Martin Paljak <***@paljak.pri.ee>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ Changes to this license can be made only by the copyright author with
+ explicit written consent.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+---
+
+Files in directory libccid/ are from the CCID project
+http://pcsclite.alioth.debian.org/ccid.html and are copyrighted by:
+- Ludovic Rousseau <***@free.fr>
+- Olaf Kirch <***@suse.de>
+- Andreas Jellinghaus <***@dungeon.inka.de>
+- Matthias Bruestle
+- Carlos Prados <***@yahoo.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
diff --git a/MdeModulePkg/Library/SmartCardReader/SmartCardReader.inf b/MdeModulePkg/Library/SmartCardReader/SmartCardReader.inf
new file mode 100644
index 0000000..6912f64
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/SmartCardReader.inf
@@ -0,0 +1,97 @@
+# Copyright (c) 2014, Gemalto. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+## @file
+# TODO: Brief Description of UEFI Driver SmartCardReader
+#
+# TODO: Detailed Description of UEFI Driver SmartCardReader
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmartCardReader
+ FILE_GUID = bb902a5e-f073-11e3-9373-5cf9dd714e6f
+ MODULE_TYPE = UEFI_DRIVER
+
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SmartCardReaderDriverEntryPoint
+ UNLOAD_IMAGE = SmartCardReaderUnload
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[Sources]
+ CcidDriver.h
+ CcidDriver.c
+ ComponentName.c
+ ComponentName.h
+ debug.c
+ SmartCardReader_impl.c
+ SmartCardReader_impl.h
+ libccid/ccid.c
+ libccid/ccid.h
+ libccid/ccid_uefi.c
+ libccid/ccid_uefi.h
+ libccid/ccid_uefi.h
+ libccid/commands.c
+ libccid/commands.h
+ libccid/ifdhandler.c
+ libccid/openct/buffer.c
+ libccid/openct/buffer.h
+ libccid/openct/checksum.c
+ libccid/openct/checksum.h
+ libccid/openct/proto-t1.c
+ libccid/openct/proto-t1.h
+ libccid/towitoko/atr.c
+ libccid/towitoko/atr.h
+ libccid/towitoko/pps.c
+ libccid/towitoko/pps.h
+ libccid/utils.c
+ libccid/utils.h
+
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ DevicePathLib
+ DebugLib
+
+
+[Protocols]
+ gEfiDriverBindingProtocolGuid
+ gEfiUsbIoProtocolGuid
+ gEfiComponentName2ProtocolGuid
+ gEfiComponentNameProtocolGuid
+ gEfiSmartCardReaderProtocolGuid
+
+[Guids]
+
diff --git a/MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.c b/MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.c
new file mode 100644
index 0000000..4387128
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.c
@@ -0,0 +1,453 @@
+/*
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "CcidDriver.h"
+#include "SmartCardReader_impl.h"
+#include <Protocol/SmartCardReader.h>
+
+#include "debuglog.h"
+#include "ifdhandler.h"
+#include "utils.h"
+#include "commands.h"
+#include "ccid.h"
+#include "atr.h"
+#include "defs.h"
+
+#define CheckThis if (NULL == This) return EFI_INVALID_PARAMETER
+
+static
+void
+update_state(
+ USB_CCID_DEV *UsbCcidDevice
+ )
+{
+ INTN reader_index;
+ RESPONSECODE response;
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+
+ UsbCcidDevice->State = SCARD_UNKNOWN;
+
+ if (-1 == (reader_index = LunToReaderIndex(UsbCcidDevice->Lun))) {
+ return;
+ }
+
+ response = CmdGetSlotStatus(reader_index, pcbuffer);
+
+ if (response != IFD_SUCCESS) {
+ return;
+ }
+
+ switch (pcbuffer[7] & CCID_ICC_STATUS_MASK) { /* bStatus */
+ case CCID_ICC_PRESENT_ACTIVE:
+ UsbCcidDevice->State = SCARD_ACTIVE;
+ break;
+ case CCID_ICC_PRESENT_INACTIVE:
+ UsbCcidDevice->State = SCARD_INACTIVE;
+ UsbCcidDevice->AtrLength = 0;
+ break;
+ case CCID_ICC_ABSENT:
+ UsbCcidDevice->State = SCARD_ABSENT;
+ UsbCcidDevice->AtrLength = 0;
+ break;
+ }
+}
+
+EFI_STATUS
+EFIAPI
+SCardConnect (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ IN UINT32 AccessMode,
+ IN UINT32 CardAction,
+ IN UINT32 PreferredProtocols,
+ OUT UINT32 *ActiveProtocol
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ RESPONSECODE response;
+ USB_CCID_DEV *UsbCcidDevice;
+ int protocol, availableProtocols;
+ ATR_t atr;
+
+ Log0(PCSC_LOG_DEBUG);
+
+ /* Check parameters */
+ CheckThis;
+
+ /* Invalid card actions */
+ if ((SCARD_CA_UNPOWER == CardAction) || (SCARD_CA_EJECT == CardAction)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbCcidDevice = USB_CCID_DEV_FROM_SMART_CARD_READER_PROTOCOL (This);
+
+ /* Already used by another SCardConnect */
+ if (UsbCcidDevice->InUse) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ UsbCcidDevice->InUse = 1;
+
+ /* Access the reader: nothing to do */
+ if (SCARD_AM_READER == AccessMode) {
+ return EFI_SUCCESS;
+ }
+
+ if (AccessMode != SCARD_AM_CARD) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Perform the CardAction action */
+ Status = SCardDisconnect(This, CardAction);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ /* No ATR so no protocol to negociate */
+ *ActiveProtocol = SCARD_PROTOCOL_UNDEFINED;
+ if (0 == UsbCcidDevice->AtrLength) {
+ return EFI_SUCCESS;
+ }
+
+ if (ATR_OK != ATR_InitFromArray(&atr, UsbCcidDevice->Atr, UsbCcidDevice->AtrLength)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ATR_OK != ATR_GetDefaultProtocol(&atr, &protocol, &availableProtocols)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((PreferredProtocols & SCARD_PROTOCOL_T1)
+ && (availableProtocols & 1 << 1)) {
+ *ActiveProtocol = SCARD_PROTOCOL_T1;
+ protocol = SCARD_PROTOCOL_T1;
+ }
+ else
+ if ((PreferredProtocols & SCARD_PROTOCOL_T0)
+ && (availableProtocols & 1 << 0)) {
+ *ActiveProtocol = SCARD_PROTOCOL_T0;
+ protocol = SCARD_PROTOCOL_T0;
+ }
+ else {
+ return EFI_UNSUPPORTED;
+ }
+
+ switch (protocol) {
+ case SCARD_PROTOCOL_T0:
+ UsbCcidDevice->CardProtocol = T_0;
+ break;
+ case SCARD_PROTOCOL_T1:
+ UsbCcidDevice->CardProtocol = T_1;
+ break;
+ }
+ response = IFDHSetProtocolParameters(UsbCcidDevice->Lun, protocol, 0, 0, 0, 0);
+ if (response != IFD_SUCCESS) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SCardDisconnect (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ IN UINT32 CardAction
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ USB_CCID_DEV *UsbCcidDevice;
+ RESPONSECODE response;
+ DWORD length;
+
+ Log0(PCSC_LOG_DEBUG);
+
+ /* Check parameters */
+ CheckThis;
+
+ UsbCcidDevice = USB_CCID_DEV_FROM_SMART_CARD_READER_PROTOCOL (This);
+
+ UsbCcidDevice->InUse = 0;
+
+ switch (CardAction) {
+ case SCARD_CA_EJECT:
+ Status = EFI_UNSUPPORTED;
+ UsbCcidDevice->InUse = 1; /* do not release the reader. See spec */
+ break;
+
+ case SCARD_CA_NORESET:
+ break;
+
+ case SCARD_CA_COLDRESET:
+ /* Power Off */
+ response = IFDHPowerICC(UsbCcidDevice->Lun, IFD_POWER_DOWN,
+ UsbCcidDevice->Atr, &length);
+ if (response != IFD_SUCCESS) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ /* Power On */
+ response = IFDHPowerICC(UsbCcidDevice->Lun, IFD_POWER_UP,
+ UsbCcidDevice->Atr, &length);
+ if (response != IFD_SUCCESS) {
+ Status = EFI_NOT_READY;
+ }
+
+ UsbCcidDevice->AtrLength = length;
+ break;
+
+ case SCARD_CA_WARMRESET:
+ /* Reset */
+ response = IFDHPowerICC(UsbCcidDevice->Lun, IFD_RESET,
+ UsbCcidDevice->Atr, &length);
+ if (response != IFD_SUCCESS) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ UsbCcidDevice->AtrLength = length;
+ break;
+
+ case SCARD_CA_UNPOWER:
+ /* Power Off */
+ response = IFDHPowerICC(UsbCcidDevice->Lun, IFD_POWER_DOWN,
+ UsbCcidDevice->Atr, &length);
+ if (response != IFD_SUCCESS) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ UsbCcidDevice->AtrLength = 0;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SCardStatus (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ OUT CHAR16 *ReaderName,
+ IN OUT UINTN *ReaderNameLength,
+ OUT UINT32 *State,
+ OUT UINT32 *CardProtocol,
+ OUT UINT8 *Atr,
+ IN OUT UINTN *AtrLength
+ )
+{
+ USB_CCID_DEV *UsbCcidDevice;
+ UINTN old_AtrLength = 0, old_ReaderNameLength = 0;
+
+ Log0(PCSC_LOG_DEBUG);
+
+ /* Check parameters */
+ CheckThis;
+ if ((NULL == ReaderNameLength) && (NULL != ReaderName)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((NULL == AtrLength) && (NULL != Atr)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbCcidDevice = USB_CCID_DEV_FROM_SMART_CARD_READER_PROTOCOL (This);
+
+ update_state(UsbCcidDevice);
+
+ if (State) {
+ *State = UsbCcidDevice->State;
+ }
+ if (CardProtocol) {
+ *CardProtocol = UsbCcidDevice->CardProtocol;
+ }
+
+ if (AtrLength) {
+ old_AtrLength = *AtrLength;
+ *AtrLength = UsbCcidDevice->AtrLength;
+ }
+ if (old_AtrLength < UsbCcidDevice->AtrLength) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (Atr) {
+ CopyMem(Atr, UsbCcidDevice->Atr, UsbCcidDevice->AtrLength);
+ }
+
+ if (ReaderNameLength) {
+ old_ReaderNameLength = *ReaderNameLength;
+ *ReaderNameLength = UsbCcidDevice->ReaderNameLength;
+ }
+ if (old_ReaderNameLength < UsbCcidDevice->ReaderNameLength) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (ReaderName) {
+ CopyMem(ReaderName, UsbCcidDevice->ReaderName, UsbCcidDevice->ReaderNameLength);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SCardTransmit (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ IN UINT8 *CAPDU,
+ IN UINTN CAPDULength,
+ OUT UINT8 *RAPDU,
+ IN OUT UINTN *RAPDULength
+ )
+{
+ USB_CCID_DEV *UsbCcidDevice;
+ RESPONSECODE response;
+ SCARD_IO_HEADER SendPci;
+ DWORD RxLength;
+ EFI_STATUS Status = EFI_SUCCESS;
+ unsigned char RxBuffer[MAX_BUFFER_SIZE_EXTENDED];
+
+ Log0(PCSC_LOG_DEBUG);
+
+ /* Check parameters */
+ CheckThis;
+ if ((NULL == CAPDU) || (0 == CAPDULength)
+ || (NULL == RAPDU) || (NULL == RAPDULength)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbCcidDevice = USB_CCID_DEV_FROM_SMART_CARD_READER_PROTOCOL (This);
+
+ /* Check the card is present and powered */
+ update_state(UsbCcidDevice);
+ if (UsbCcidDevice->State != SCARD_ACTIVE) {
+ return EFI_NOT_READY;
+ }
+
+ RxLength = sizeof RxBuffer;
+ SendPci.Protocol = UsbCcidDevice->CardProtocol;
+ response = IFDHTransmitToICC(UsbCcidDevice->Lun, SendPci, CAPDU, CAPDULength, RxBuffer, &RxLength, NULL);
+ if (*RAPDULength < RxLength) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+ *RAPDULength = RxLength;
+
+ if (IFD_SUCCESS != response) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ else {
+ CopyMem(RAPDU, RxBuffer, RxLength);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SCardControl (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ IN UINT32 ControlCode,
+ IN UINT8 *InBuffer,
+ IN UINTN InBufferLength,
+ OUT UINT8 *OutBuffer,
+ IN OUT UINTN *OutBufferLength
+ )
+{
+ USB_CCID_DEV *UsbCcidDevice;
+ RESPONSECODE response;
+ DWORD dwBytesReturned;
+ UINTN dummy = 0;
+
+ Log0(PCSC_LOG_DEBUG);
+
+ /* Check parameters */
+ CheckThis;
+ if ((NULL == OutBuffer) && (NULL != OutBufferLength)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbCcidDevice = USB_CCID_DEV_FROM_SMART_CARD_READER_PROTOCOL (This);
+
+ /* OutBufferLength may be NULL */
+ if (NULL == OutBufferLength) {
+ OutBufferLength = &dummy;
+ }
+
+ dwBytesReturned = *OutBufferLength;
+ response = IFDHControl(UsbCcidDevice->Lun, ControlCode, InBuffer, InBufferLength, OutBuffer, *OutBufferLength, &dwBytesReturned);
+ *OutBufferLength = dwBytesReturned;
+
+ switch (response) {
+ case IFD_SUCCESS:
+ return EFI_SUCCESS;
+ case IFD_ERROR_NOT_SUPPORTED:
+ return EFI_UNSUPPORTED;
+ case IFD_ERROR_INSUFFICIENT_BUFFER:
+ return EFI_BUFFER_TOO_SMALL;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+EFI_STATUS
+EFIAPI
+SCardGetAttrib (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ IN UINT32 Attrib,
+ OUT UINT8 *OutBuffer,
+ IN OUT UINTN *OutBufferLength
+ )
+{
+ USB_CCID_DEV *UsbCcidDevice;
+ RESPONSECODE response;
+ DWORD dwBytesReturned;
+
+ Log0(PCSC_LOG_DEBUG);
+
+ /* Check parameters */
+ CheckThis;
+ if ((NULL == OutBuffer) || (NULL == OutBufferLength) || (0 == *OutBufferLength)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbCcidDevice = USB_CCID_DEV_FROM_SMART_CARD_READER_PROTOCOL (This);
+ dwBytesReturned = *OutBufferLength;
+ response = IFDHGetCapabilities(UsbCcidDevice->Lun, Attrib, &dwBytesReturned, OutBuffer);
+ *OutBufferLength = dwBytesReturned;
+
+ switch (response) {
+ case IFD_SUCCESS:
+ return EFI_SUCCESS;
+ case IFD_ERROR_TAG:
+ return EFI_UNSUPPORTED;
+ case IFD_ERROR_INSUFFICIENT_BUFFER:
+ return EFI_BUFFER_TOO_SMALL;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+}
+
diff --git a/MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.h b/MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.h
new file mode 100644
index 0000000..989a185
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.h
@@ -0,0 +1,94 @@
+/*
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _SMART_CARD_READER_IMPL_H_
+#define _SMART_CARD_READER_IMPL_H_
+
+#include <Protocol/SmartCardReader.h>
+
+EFI_STATUS
+EFIAPI
+SCardConnect (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ IN UINT32 AccessMode,
+ IN UINT32 CardAction,
+ IN UINT32 PreferredProtocols,
+ OUT UINT32 *ActiveProtocol
+);
+
+EFI_STATUS
+EFIAPI
+SCardDisconnect (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ IN UINT32 CardAction
+);
+
+EFI_STATUS
+EFIAPI
+SCardStatus (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ OUT CHAR16 *ReaderName,
+ IN OUT UINTN *ReaderNameLength,
+ OUT UINT32 *State,
+ OUT UINT32 *CardProtocol,
+ OUT UINT8 *Atr,
+ IN OUT UINTN *AtrLength
+);
+
+EFI_STATUS
+EFIAPI
+SCardTransmit (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ IN UINT8 *CAPDU,
+ IN UINTN CAPDULength,
+ OUT UINT8 *RAPDU,
+ IN OUT UINTN *RAPDULength
+);
+
+EFI_STATUS
+EFIAPI
+SCardControl (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ IN UINT32 ControlCode,
+ IN UINT8 *InBuffer,
+ IN UINTN InBufferLength,
+ OUT UINT8 *OutBuffer,
+ IN OUT UINTN *OutBufferLength
+);
+
+EFI_STATUS
+EFIAPI
+SCardGetAttrib (
+ IN EFI_SMART_CARD_READER_PROTOCOL *This,
+ IN UINT32 Attrib,
+ OUT UINT8 *OutBuffer,
+ IN OUT UINTN *OutBufferLength
+);
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/config.h b/MdeModulePkg/Library/SmartCardReader/config.h
new file mode 100644
index 0000000..b02352e
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/config.h
@@ -0,0 +1,64 @@
+/*
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* we build for the UEFI driver */
+#define UEFI_DRIVER
+
+/* no log or debug messages */
+#define NO_LOG
+
+/* Adapt types used in libccid/ to UEFI types */
+#define size_t long
+#ifndef uint8_t
+#define uint8_t unsigned char
+#endif
+#define uint32_t UINT32
+
+#define MAX_BUFFER_SIZE_EXTENDED (4 + 3 + (1<<16) + 3 + 2) /**< enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer */
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+/* Use UEFI functions instead of C/Unix ones */
+#define free(a) FreePool(a)
+#define getenv(a) NULL
+#define malloc(a) AllocateZeroPool(a)
+#define memcpy CopyMem
+#define memmove CopyMem
+#define memset(buffer, value, length) SetMem(buffer, length, value)
+#define sleep(a) a
+#define strncmp(s1, s2, n) -1
+#define strerror(a) ""
+#define memcmp CompareMem
+
+/* TODO */
+#define usleep(a) 1
+#define ENODEV -1
+#define errno -1
+#define htonl(a) (a)
+
diff --git a/MdeModulePkg/Library/SmartCardReader/debug.c b/MdeModulePkg/Library/SmartCardReader/debug.c
new file mode 100644
index 0000000..a45e545
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/debug.c
@@ -0,0 +1,62 @@
+/*
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+#include "debuglog.h"
+
+#include <Library/UefiLib.h>
+
+void
+log_xxd(
+ const int priority,
+ const char *msg,
+ const unsigned char *buffer,
+ const int len)
+{
+ UINTN i;
+
+ (void)priority;
+
+ switch(msg[0])
+ {
+ case '>':
+ Print(L"-> ");
+ break;
+ case '<':
+ Print(L"<- ");
+ break;
+ }
+
+ for (i = 0; i < len; ++i)
+ {
+ /* 2 hex characters, 1 space, 1 NUL : total 4 characters */
+ Print(L" %02X", buffer[i]);
+ }
+
+ Print(L"\n");
+} /* log_xxd */
diff --git a/MdeModulePkg/Library/SmartCardReader/debuglog.h b/MdeModulePkg/Library/SmartCardReader/debuglog.h
new file mode 100644
index 0000000..a0a2a70
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/debuglog.h
@@ -0,0 +1,81 @@
+/*
+Copyright (c) 2014, Gemalto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** @file
+ TODO: Brief Description of UEFI Driver SmartCardReader
+
+ TODO: Detailed Description of UEFI Driver SmartCardReader
+
+**/
+
+#ifndef __EFI_DEBUGLOG_H__
+#define __EFI_DEBUGLOG_H__
+
+#include "config.h"
+#include <Uefi.h>
+
+//
+// Libraries
+//
+#include <Library/DebugLib.h>
+
+
+
+/* Debug macros */
+#ifdef NO_LOG
+
+#define Log0(priority) do { } while(0)
+#define Log1(priority, fmt) do { } while(0)
+#define Log2(priority, fmt, data) do { } while(0)
+#define Log3(priority, fmt, data1, data2) do { } while(0)
+#define Log4(priority, fmt, data1, data2, data3) do { } while(0)
+#define Log5(priority, fmt, data1, data2, data3, data4) do { } while(0)
+#define Log9(priority, fmt, data1, data2, data3, data4, data5, data6, data7, data8) do { } while(0)
+#define LogXxd(priority, msg, buffer, size) do { } while(0)
+
+#else
+
+#define Log0(priority) DEBUG((priority, "%d:%a()\n", __LINE__, __FUNCTION__))
+#define Log1(priority, fmt) DEBUG((priority, "%d:%a() " fmt "\n", __LINE__, __FUNCTION__))
+#define Log2(priority, fmt, data) DEBUG((priority, "%d:%a() " fmt "\n", __LINE__, __FUNCTION__, data))
+#define Log3(priority, fmt, data1, data2) DEBUG((priority, "%d:%a() " fmt "\n", __LINE__, __FUNCTION__, data1, data2))
+#define Log4(priority, fmt, data1, data2, data3) DEBUG((priority, "%d:%a() " fmt "\n", __LINE__, __FUNCTION__, data1, data2, data3))
+#define Log5(priority, fmt, data1, data2, data3, data4) DEBUG((priority, "%d:%a() " fmt "\n", __LINE__, __FUNCTION__, data1, data2, data3, data4))
+#define Log9(priority, fmt, data1, data2, data3, data4, data5, data6, data7, data8) DEBUG((priority, "%d:%a() " fmt "\n", __LINE__, __FUNCTION__, data1, data2, data3, data4, data5, data6, data7, data8))
+#define LogXxd(priority, msg, buffer, size) log_xxd((priority, msg, buffer, size))
+#endif
+
+#define PCSC_LOG_DEBUG EFI_D_WARN
+#define PCSC_LOG_INFO EFI_D_INFO
+#define PCSC_LOG_ERROR EFI_D_ERROR
+#define PCSC_LOG_CRITICAL EFI_D_ERROR
+
+void log_xxd(const int priority, const char *msg,
+ const unsigned char *buffer, const int size);
+
+#endif
--
2.1.4


------------------------------------------------------------------------------
Ludovic Rousseau
2015-06-10 18:27:43 UTC
Permalink
MdeModulePkg/Library/SmartCardReader/ provides an implementation of
EFI_SMART_CARD_READER_PROTOCOL.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ludovic Rousseau <***@gmail.com>
---
MdeModulePkg/MdeModulePkg.dsc | 1 +
1 file changed, 1 insertion(+)

diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index f718b3e..3b0981a 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -358,6 +358,7 @@
MdeModulePkg/Universal/EsrtDxe/EsrtDxe.inf

MdeModulePkg/Universal/PropertiesTableAttributesDxe/PropertiesTableAttributesDxe.inf
+ MdeModulePkg/Library/SmartCardReader/SmartCardReader.inf

[Components.IA32, Components.X64, Components.IPF]
MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf
--
2.1.4


------------------------------------------------------------------------------
Ludovic Rousseau
2015-06-10 18:27:40 UTC
Permalink
libccid project is hosted at http://pcsclite.alioth.debian.org/ccid.html

This code is shared with the libccid project. In order to easily port
changes between libccid and UEFI projects I decided to keep the coding
style as it was and not strictly comply to the UEFI coding style.

Contributed-under: GNU LGPL v2.1+
Signed-off-by: Ludovic Rousseau <***@gmail.com>
---
.../Library/SmartCardReader/libccid/ccid.c | 659 ++++++
.../Library/SmartCardReader/libccid/ccid.h | 340 +++
.../SmartCardReader/libccid/ccid_ifdhandler.h | 63 +
.../Library/SmartCardReader/libccid/ccid_uefi.c | 470 ++++
.../Library/SmartCardReader/libccid/ccid_uefi.h | 46 +
.../Library/SmartCardReader/libccid/commands.c | 2294 ++++++++++++++++++++
.../Library/SmartCardReader/libccid/commands.h | 64 +
.../Library/SmartCardReader/libccid/debug.c | 157 ++
.../Library/SmartCardReader/libccid/debug.h | 100 +
.../Library/SmartCardReader/libccid/defs.h | 126 ++
.../Library/SmartCardReader/libccid/ifdhandler.c | 2265 +++++++++++++++++++
.../Library/SmartCardReader/libccid/openct/LICENSE | 28 +
.../Library/SmartCardReader/libccid/openct/README | 7 +
.../SmartCardReader/libccid/openct/buffer.c | 73 +
.../SmartCardReader/libccid/openct/buffer.h | 36 +
.../SmartCardReader/libccid/openct/checksum.c | 95 +
.../SmartCardReader/libccid/openct/checksum.h | 37 +
.../SmartCardReader/libccid/openct/proto-t1.c | 800 +++++++
.../SmartCardReader/libccid/openct/proto-t1.h | 85 +
.../SmartCardReader/libccid/towitoko/COPYING | 505 +++++
.../SmartCardReader/libccid/towitoko/README | 14 +
.../Library/SmartCardReader/libccid/towitoko/atr.c | 365 ++++
.../Library/SmartCardReader/libccid/towitoko/atr.h | 111 +
.../SmartCardReader/libccid/towitoko/defines.h | 56 +
.../Library/SmartCardReader/libccid/towitoko/pps.c | 136 ++
.../Library/SmartCardReader/libccid/towitoko/pps.h | 71 +
.../Library/SmartCardReader/libccid/utils.c | 85 +
.../Library/SmartCardReader/libccid/utils.h | 33 +
28 files changed, 9121 insertions(+)
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/commands.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/commands.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/debug.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/debug.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/defs.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/README
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/utils.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/utils.h

diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ccid.c b/MdeModulePkg/Library/SmartCardReader/libccid/ccid.c
new file mode 100644
index 0000000..eff9050
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ccid.c
@@ -0,0 +1,659 @@
+/*
+ ccid.c: CCID common code
+ Copyright (C) 2003-2010 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: ccid.c 6976 2014-09-04 11:35:46Z rousseau $
+ */
+
+#include <config.h>
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <pcsclite.h>
+#include <ifdhandler.h>
+
+#include "debug.h"
+#include "ccid.h"
+#include "defs.h"
+#include "ccid_ifdhandler.h"
+#include "commands.h"
+#include "utils.h"
+
+#ifdef __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+/*****************************************************************************
+ *
+ * ccid_open_hack_pre
+ *
+ ****************************************************************************/
+int ccid_open_hack_pre(unsigned int reader_index)
+{
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ switch (ccid_descriptor->readerID)
+ {
+ case MYSMARTPAD:
+ ccid_descriptor->dwMaxIFSD = 254;
+ break;
+
+ case CL1356D:
+ /* the firmware needs some time to initialize */
+ (void)sleep(1);
+ ccid_descriptor->readTimeout = 60*1000; /* 60 seconds */
+ break;
+
+ case GEMPCTWIN:
+ case GEMPCKEY:
+ case DELLSCRK:
+ /* Only the chipset with firmware version 2.00 is "bogus"
+ * The reader may send packets of 0 bytes when the reader is
+ * connected to a USB 3 port */
+ if (0x0200 == ccid_descriptor->IFD_bcdDevice)
+ {
+ ccid_descriptor->zlp = TRUE;
+ DEBUG_INFO1("ZLP fixup");
+ }
+ break;
+
+ case OZ776_7772:
+ ccid_descriptor->dwMaxDataRate = 9600;
+ break;
+ }
+
+ /* CCID */
+ if ((PROTOCOL_CCID == ccid_descriptor->bInterfaceProtocol)
+ && (3 == ccid_descriptor -> bNumEndpoints))
+ {
+#ifndef TWIN_SERIAL
+ /* just wait for 100ms in case a notification is in the pipe */
+ (void)InterruptRead(reader_index, 100);
+#endif
+ }
+
+ /* ICCD type A */
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char tmp[MAX_ATR_SIZE];
+ unsigned int n = sizeof(tmp);
+
+ DEBUG_COMM("ICCD type A");
+ (void)CmdPowerOff(reader_index);
+ (void)CmdPowerOn(reader_index, &n, tmp, CCID_CLASS_AUTO_VOLTAGE);
+ (void)CmdPowerOff(reader_index);
+ }
+
+ /* ICCD type B */
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char tmp[MAX_ATR_SIZE];
+ unsigned int n = sizeof(tmp);
+
+ DEBUG_COMM("ICCD type B");
+ if (CCID_CLASS_SHORT_APDU ==
+ (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK))
+ {
+ /* use the extended APDU comm alogorithm */
+ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK;
+ ccid_descriptor->dwFeatures |= CCID_CLASS_EXTENDED_APDU;
+ }
+
+ (void)CmdPowerOff(reader_index);
+ (void)CmdPowerOn(reader_index, &n, tmp, CCID_CLASS_AUTO_VOLTAGE);
+ (void)CmdPowerOff(reader_index);
+ }
+
+ return 0;
+} /* ccid_open_hack_pre */
+
+#ifndef NO_LOG
+/*****************************************************************************
+ *
+ * dump_gemalto_firmware_features
+ *
+ ****************************************************************************/
+static void dump_gemalto_firmware_features(struct GEMALTO_FIRMWARE_FEATURES *gff)
+{
+ DEBUG_INFO2("Dumping Gemalto firmware features (%zd bytes):",
+ sizeof(struct GEMALTO_FIRMWARE_FEATURES));
+
+#ifdef UEFI_DRIVER
+#define YESNO(x) (x) ? L"yes" : L"no"
+#else
+#define YESNO(x) (x) ? "yes" : "no"
+#endif
+
+ DEBUG_INFO2(" bLogicalLCDLineNumber: %d", gff->bLogicalLCDLineNumber);
+ DEBUG_INFO2(" bLogicalLCDRowNumber: %d", gff->bLogicalLCDRowNumber);
+ DEBUG_INFO2(" bLcdInfo: 0x%02X", gff->bLcdInfo);
+ DEBUG_INFO2(" bEntryValidationCondition: 0x%02X",
+ gff->bEntryValidationCondition);
+
+ DEBUG_INFO1(" Reader supports PC/SCv2 features:");
+ DEBUG_INFO2(" VerifyPinStart: %s", YESNO(gff->VerifyPinStart));
+ DEBUG_INFO2(" VerifyPinFinish: %s", YESNO(gff->VerifyPinFinish));
+ DEBUG_INFO2(" ModifyPinStart: %s", YESNO(gff->ModifyPinStart));
+ DEBUG_INFO2(" ModifyPinFinish: %s", YESNO(gff->ModifyPinFinish));
+ DEBUG_INFO2(" GetKeyPressed: %s", YESNO(gff->GetKeyPressed));
+ DEBUG_INFO2(" VerifyPinDirect: %s", YESNO(gff->VerifyPinDirect));
+ DEBUG_INFO2(" ModifyPinDirect: %s", YESNO(gff->ModifyPinDirect));
+ DEBUG_INFO2(" Abort: %s", YESNO(gff->Abort));
+ DEBUG_INFO2(" GetKey: %s", YESNO(gff->GetKey));
+ DEBUG_INFO2(" WriteDisplay: %s", YESNO(gff->WriteDisplay));
+ DEBUG_INFO2(" SetSpeMessage: %s", YESNO(gff->SetSpeMessage));
+ DEBUG_INFO2(" bTimeOut2: %s", YESNO(gff->bTimeOut2));
+ DEBUG_INFO2(" bPPDUSupportOverXferBlock: %s",
+ YESNO(gff->bPPDUSupportOverXferBlock));
+ DEBUG_INFO2(" bPPDUSupportOverEscape: %s",
+ YESNO(gff->bPPDUSupportOverEscape));
+
+ DEBUG_INFO2(" bListSupportedLanguages: %s",
+ YESNO(gff->bListSupportedLanguages));
+ DEBUG_INFO2(" bNumberMessageFix: %s", YESNO(gff->bNumberMessageFix));
+
+ DEBUG_INFO2(" VersionNumber: 0x%02X", gff->VersionNumber);
+ DEBUG_INFO2(" MinimumPINSize: %d", gff->MinimumPINSize);
+ DEBUG_INFO2(" MaximumPINSize: %d", gff->MaximumPINSize);
+ DEBUG_INFO2(" Firewall: %s", YESNO(gff->Firewall));
+ if (gff->Firewall && gff->FirewalledCommand_SW1
+ && gff->FirewalledCommand_SW2)
+ {
+ DEBUG_INFO2(" FirewalledCommand_SW1: 0x%02X",
+ gff->FirewalledCommand_SW1);
+ DEBUG_INFO2(" FirewalledCommand_SW2: 0x%02X",
+ gff->FirewalledCommand_SW2);
+ }
+
+} /* dump_gemalto_firmware_features */
+#endif
+
+/*****************************************************************************
+ *
+ * set_gemalto_firmware_features
+ *
+ ****************************************************************************/
+static void set_gemalto_firmware_features(unsigned int reader_index)
+{
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ struct GEMALTO_FIRMWARE_FEATURES *gf_features;
+
+ gf_features = malloc(sizeof(struct GEMALTO_FIRMWARE_FEATURES));
+ if (gf_features)
+ {
+ unsigned char cmd[] = { 0x6A }; /* GET_FIRMWARE_FEATURES command id */
+ unsigned int len_features = sizeof *gf_features;
+ RESPONSECODE ret;
+
+ ret = CmdEscape(reader_index, cmd, sizeof cmd,
+ (unsigned char*)gf_features, &len_features, 0);
+ if ((IFD_SUCCESS == ret) &&
+ (len_features == sizeof *gf_features))
+ {
+ /* Command is supported if it succeeds at CCID level */
+ /* and returned size matches our expectation */
+ ccid_descriptor->gemalto_firmware_features = gf_features;
+#ifndef NO_LOG
+ dump_gemalto_firmware_features(gf_features);
+#endif
+ }
+ else
+ {
+ /* Command is not supported, let's free allocated memory */
+ free(gf_features);
+ DEBUG_INFO3("GET_FIRMWARE_FEATURES failed: " DWORD_D ", len=%d",
+ ret, len_features);
+ }
+ }
+} /* set_gemalto_firmware_features */
+
+/*****************************************************************************
+ *
+ * ccid_open_hack_post
+ *
+ ****************************************************************************/
+int ccid_open_hack_post(unsigned int reader_index)
+{
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ RESPONSECODE return_value = IFD_SUCCESS;
+
+ switch (ccid_descriptor->readerID)
+ {
+ case GEMPCKEY:
+ case GEMPCTWIN:
+ /* Reader announces TPDU but can do APDU (EMV in fact) */
+ if (DriverOptions & DRIVER_OPTION_GEMPC_TWIN_KEY_APDU)
+ {
+ unsigned char cmd[] = { 0x1F, 0x02 };
+ unsigned char res[10];
+ unsigned int length_res = sizeof(res);
+
+ if (CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, 0) == IFD_SUCCESS)
+ {
+ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK;
+ ccid_descriptor->dwFeatures |= CCID_CLASS_SHORT_APDU;
+ }
+ }
+ break;
+
+ case VEGAALPHA:
+ case GEMPCPINPAD:
+ /* load the l10n strings in the pinpad memory */
+ {
+#define L10N_HEADER_SIZE 5
+#define L10N_STRING_MAX_SIZE 16
+#define L10N_NB_STRING 10
+
+ unsigned char cmd[L10N_HEADER_SIZE + L10N_NB_STRING * L10N_STRING_MAX_SIZE];
+ unsigned char res[20];
+ unsigned int length_res = sizeof(res);
+ int offset, i, j;
+
+ const char *fr[] = {
+ "Entrer PIN",
+ "Nouveau PIN",
+ "Confirmer PIN",
+ "PIN correct",
+ "PIN Incorrect !",
+ "Delai depasse",
+ "* essai restant",
+ "Inserer carte",
+ "Erreur carte",
+ "PIN bloque" };
+
+ const char *de[] = {
+ "PIN eingeben",
+ "Neue PIN",
+ "PIN bestatigen",
+ "PIN korrect",
+ "Falsche PIN !",
+ "Zeit abgelaufen",
+ "* Versuche ubrig",
+ "Karte einstecken",
+ "Fehler Karte",
+ "PIN blockiert" };
+
+ const char *es[] = {
+ "Introducir PIN",
+ "Nuevo PIN",
+ "Confirmar PIN",
+ "PIN OK",
+ "PIN Incorrecto !",
+ "Tiempo Agotado",
+ "* ensayos quedan",
+ "Introducir Tarj.",
+ "Error en Tarjeta",
+ "PIN bloqueado" };
+
+ const char *it[] = {
+ "Inserire PIN",
+ "Nuovo PIN",
+ "Confermare PIN",
+ "PIN Corretto",
+ "PIN Errato !",
+ "Tempo scaduto",
+ "* prove rimaste",
+ "Inserire Carta",
+ "Errore Carta",
+ "PIN ostruito"};
+
+ const char *pt[] = {
+ "Insira PIN",
+ "Novo PIN",
+ "Conf. novo PIN",
+ "PIN OK",
+ "PIN falhou!",
+ "Tempo expirou",
+ "* tentiv. restam",
+ "Introduza cartao",
+ "Erro cartao",
+ "PIN bloqueado" };
+
+ const char *nl[] = {
+ "Inbrengen code",
+ "Nieuwe code",
+ "Bevestig code",
+ "Code aanvaard",
+ "Foute code",
+ "Time out",
+ "* Nog Pogingen",
+ "Kaart inbrengen",
+ "Kaart fout",
+ "Kaart blok" };
+
+ const char *tr[] = {
+ "PIN Giriniz",
+ "Yeni PIN",
+ "PIN Onayala",
+ "PIN OK",
+ "Yanlis PIN",
+ "Zaman Asimi",
+ "* deneme kaldi",
+ "Karti Takiniz",
+ "Kart Hatasi",
+ "Kart Kilitli" };
+
+ const char *en[] = {
+ "Enter PIN",
+ "New PIN",
+ "Confirm PIN",
+ "PIN OK",
+ "Incorrect PIN!",
+ "Time Out",
+ "* retries left",
+ "Insert Card",
+ "Card Error",
+ "PIN blocked" };
+
+ const char *lang;
+ const char **l10n;
+
+#ifdef __APPLE__
+ CFArrayRef cfa;
+ CFStringRef slang;
+
+ /* Get the complete ordered list */
+ cfa = CFLocaleCopyPreferredLanguages();
+
+ /* Use the first/preferred language
+ * As the driver is run as root we get the language
+ * selected during install */
+ slang = CFArrayGetValueAtIndex(cfa, 0);
+
+ /* CFString -> C string */
+ lang = CFStringGetCStringPtr(slang, kCFStringEncodingMacRoman);
+#else
+ /* The other Unixes just use the LANG env variable */
+ lang = getenv("LANG");
+#endif
+ DEBUG_COMM2("Using lang: %s", lang);
+ if (NULL == lang)
+ l10n = en;
+ else
+ {
+ if (0 == strncmp(lang, "fr", 2))
+ l10n = fr;
+ else if (0 == strncmp(lang, "de", 2))
+ l10n = de;
+ else if (0 == strncmp(lang, "es", 2))
+ l10n = es;
+ else if (0 == strncmp(lang, "it", 2))
+ l10n = it;
+ else if (0 == strncmp(lang, "pt", 2))
+ l10n = pt;
+ else if (0 == strncmp(lang, "nl", 2))
+ l10n = nl;
+ else if (0 == strncmp(lang, "tr", 2))
+ l10n = tr;
+ else
+ l10n = en;
+ }
+
+#ifdef __APPLE__
+ /* Release the allocated array */
+ CFRelease(cfa);
+#endif
+ offset = 0;
+ cmd[offset++] = 0xB2; /* load strings */
+ cmd[offset++] = 0xA0; /* address of the memory */
+ cmd[offset++] = 0x00; /* address of the first byte */
+ cmd[offset++] = 0x4D; /* magic value */
+ cmd[offset++] = 0x4C; /* magic value */
+
+ /* for each string */
+ for (i=0; i<L10N_NB_STRING; i++)
+ {
+ /* copy the string */
+ for (j=0; l10n[i][j]; j++)
+ cmd[offset++] = l10n[i][j];
+
+ /* pad with " " */
+ for (; j<L10N_STRING_MAX_SIZE; j++)
+ cmd[offset++] = ' ';
+ }
+
+ (void)sleep(1);
+ if (IFD_SUCCESS == CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, DEFAULT_COM_READ_TIMEOUT))
+ {
+ DEBUG_COMM("l10n string loaded successfully");
+ }
+ else
+ {
+ DEBUG_COMM("Failed to load l10n strings");
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+
+ if (DriverOptions & DRIVER_OPTION_DISABLE_PIN_RETRIES)
+ {
+ /* disable VERIFY from reader */
+ const unsigned char cmd2[] = {0xb5, 0x00};
+ length_res = sizeof(res);
+ if (IFD_SUCCESS == CmdEscape(reader_index, cmd2, sizeof(cmd2), res, &length_res, DEFAULT_COM_READ_TIMEOUT))
+ {
+ DEBUG_COMM("Disable SPE retry counter successfull");
+ }
+ else
+ {
+ DEBUG_CRITICAL("Failed to disable SPE retry counter");
+ }
+ }
+ }
+ break;
+
+ case HPSMARTCARDKEYBOARD:
+ case HP_CCIDSMARTCARDKEYBOARD:
+ case FUJITSUSMARTKEYB:
+ /* the Secure Pin Entry is bogus so disable it
+ * http://martinpaljak.net/2011/03/19/insecure-hp-usb-smart-card-keyboard/
+ */
+ ccid_descriptor->bPINSupport = 0;
+ break;
+
+#if 0
+ /* SCM SCR331-DI contactless */
+ case SCR331DI:
+ /* SCM SCR331-DI-NTTCOM contactless */
+ case SCR331DINTTCOM:
+ /* SCM SDI010 contactless */
+ case SDI010:
+ /* the contactless reader is in the second slot */
+ if (ccid_descriptor->bCurrentSlotIndex > 0)
+ {
+ unsigned char cmd1[] = { 0x00 };
+ /* command: 00 ??
+ * response: 06 10 03 03 00 00 00 01 FE FF FF FE 01 ?? */
+ unsigned char cmd2[] = { 0x02 };
+ /* command: 02 ??
+ * response: 00 ?? */
+
+ unsigned char res[20];
+ unsigned int length_res = sizeof(res);
+
+ if ((IFD_SUCCESS == CmdEscape(reader_index, cmd1, sizeof(cmd1), res, &length_res, 0))
+ && (IFD_SUCCESS == CmdEscape(reader_index, cmd2, sizeof(cmd2), res, &length_res, 0)))
+ {
+ DEBUG_COMM("SCM SCR331-DI contactless detected");
+ }
+ else
+ {
+ DEBUG_COMM("SCM SCR331-DI contactless init failed");
+ }
+
+ /* hack since the contactless reader do not share dwFeatures */
+ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK;
+ ccid_descriptor->dwFeatures |= CCID_CLASS_SHORT_APDU;
+
+ ccid_descriptor->dwFeatures |= CCID_CLASS_AUTO_IFSD;
+ }
+ break;
+#endif
+ }
+
+ /* Gemalto readers may report additional information */
+ if (GET_VENDOR(ccid_descriptor->readerID) == VENDOR_GEMALTO)
+ set_gemalto_firmware_features(reader_index);
+
+ return return_value;
+} /* ccid_open_hack_post */
+
+/*****************************************************************************
+ *
+ * ccid_error
+ *
+ ****************************************************************************/
+void ccid_error(int error, const char *file, int line, const char *function)
+{
+#ifndef NO_LOG
+ const char *text;
+ char var_text[30];
+
+ switch (error)
+ {
+ case 0x00:
+ text = "Command not supported or not allowed";
+ break;
+
+ case 0x01:
+ text = "Wrong command length";
+ break;
+
+ case 0x05:
+ text = "Invalid slot number";
+ break;
+
+ case 0xA2:
+ text = "Card short-circuiting. Card powered off";
+ break;
+
+ case 0xA3:
+ text = "ATR too long (> 33)";
+ break;
+
+ case 0xAB:
+ text = "No data exchanged";
+ break;
+
+ case 0xB0:
+ text = "Reader in EMV mode and T=1 message too long";
+ break;
+
+ case 0xBB:
+ text = "Protocol error in EMV mode";
+ break;
+
+ case 0xBD:
+ text = "Card error during T=1 exchange";
+ break;
+
+ case 0xBE:
+ text = "Wrong APDU command length";
+ break;
+
+ case 0xE0:
+ text = "Slot busy";
+ break;
+
+ case 0xEF:
+ text = "PIN cancelled";
+ break;
+
+ case 0xF0:
+ text = "PIN timeout";
+ break;
+
+ case 0xF2:
+ text = "Busy with autosequence";
+ break;
+
+ case 0xF3:
+ text = "Deactivated protocol";
+ break;
+
+ case 0xF4:
+ text = "Procedure byte conflict";
+ break;
+
+ case 0xF5:
+ text = "Class not supported";
+ break;
+
+ case 0xF6:
+ text = "Protocol not supported";
+ break;
+
+ case 0xF7:
+ text = "Invalid ATR checksum byte (TCK)";
+ break;
+
+ case 0xF8:
+ text = "Invalid ATR first byte";
+ break;
+
+ case 0xFB:
+ text = "Hardware error";
+ break;
+
+ case 0xFC:
+ text = "Overrun error";
+ break;
+
+ case 0xFD:
+ text = "Parity error during exchange";
+ break;
+
+ case 0xFE:
+ text = "Card absent or mute";
+ break;
+
+ case 0xFF:
+ text = "Activity aborted by Host";
+ break;
+
+ default:
+#ifndef UEFI_DRIVER
+ if ((error >= 1) && (error <= 127))
+ (void)snprintf(var_text, sizeof(var_text), "error on byte %d",
+ error);
+ else
+ (void)snprintf(var_text, sizeof(var_text),
+ "Unknown CCID error: 0x%02X", error);
+#endif
+
+ text = var_text;
+ break;
+ }
+#ifndef UEFI_DRIVER
+ log_msg(PCSC_LOG_ERROR, "%s:%d:%s %s", file, line, function, text);
+#endif
+
+#endif
+
+} /* ccid_error */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ccid.h b/MdeModulePkg/Library/SmartCardReader/libccid/ccid.h
new file mode 100644
index 0000000..0dc644c
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ccid.h
@@ -0,0 +1,340 @@
+/*
+ ccid.h: CCID structures
+ Copyright (C) 2003-2010 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: ccid.h 6845 2014-02-14 09:16:01Z rousseau $
+ */
+
+typedef struct
+{
+ /*
+ * CCID Sequence number
+ */
+ unsigned char *pbSeq;
+ unsigned char real_bSeq;
+
+ /*
+ * VendorID << 16 + ProductID
+ */
+ int readerID;
+
+ /*
+ * Maximum message length
+ */
+ unsigned int dwMaxCCIDMessageLength;
+
+ /*
+ * Maximum IFSD
+ */
+ int dwMaxIFSD;
+
+ /*
+ * Features supported by the reader (directly from Class Descriptor)
+ */
+ int dwFeatures;
+
+ /*
+ * PIN support of the reader (directly from Class Descriptor)
+ */
+ char bPINSupport;
+
+ /*
+ * Display dimensions of the reader (directly from Class Descriptor)
+ */
+ unsigned int wLcdLayout;
+
+ /*
+ * Default Clock
+ */
+ int dwDefaultClock;
+
+ /*
+ * Max Data Rate
+ */
+ unsigned int dwMaxDataRate;
+
+ /*
+ * Number of available slots
+ */
+ char bMaxSlotIndex;
+
+ /*
+ * Slot in use
+ */
+ char bCurrentSlotIndex;
+
+ /*
+ * The array of data rates supported by the reader
+ */
+ unsigned int *arrayOfSupportedDataRates;
+
+ /*
+ * Read communication port timeout
+ * value is milliseconds
+ * this value can evolve dynamically if card request it (time processing).
+ */
+ unsigned int readTimeout;
+
+ /*
+ * Card protocol
+ */
+ int cardProtocol;
+
+ /*
+ * bInterfaceProtocol (CCID, ICCD-A, ICCD-B)
+ */
+ int bInterfaceProtocol;
+
+ /*
+ * bNumEndpoints
+ */
+ int bNumEndpoints;
+
+ /*
+ * GemCore SIM PRO slot status management
+ * The reader always reports a card present even if no card is inserted.
+ * If the Power Up fails the driver will report IFD_ICC_NOT_PRESENT instead
+ * of IFD_ICC_PRESENT
+ */
+ int dwSlotStatus;
+
+ /*
+ * bVoltageSupport (bit field)
+ * 1 = 5.0V
+ * 2 = 3.0V
+ * 4 = 1.8V
+ */
+ int bVoltageSupport;
+
+ /*
+ * USB serial number of the device (if any)
+ */
+ char *sIFD_serial_number;
+
+ /*
+ * USB iManufacturer string
+ */
+ char *sIFD_iManufacturer;
+
+ /*
+ * USB bcdDevice
+ */
+ int IFD_bcdDevice;
+
+ /*
+ * Gemalto extra features, if any
+ */
+ struct GEMALTO_FIRMWARE_FEATURES *gemalto_firmware_features;
+
+ /*
+ * Zero Length Packet fixup (boolean)
+ */
+ char zlp;
+} _ccid_descriptor;
+
+/* Features from dwFeatures */
+#define CCID_CLASS_AUTO_CONF_ATR 0x00000002
+#define CCID_CLASS_AUTO_VOLTAGE 0x00000008
+#define CCID_CLASS_AUTO_BAUD 0x00000020
+#define CCID_CLASS_AUTO_PPS_PROP 0x00000040
+#define CCID_CLASS_AUTO_PPS_CUR 0x00000080
+#define CCID_CLASS_AUTO_IFSD 0x00000400
+#define CCID_CLASS_CHARACTER 0x00000000
+#define CCID_CLASS_TPDU 0x00010000
+#define CCID_CLASS_SHORT_APDU 0x00020000
+#define CCID_CLASS_EXTENDED_APDU 0x00040000
+#define CCID_CLASS_EXCHANGE_MASK 0x00070000
+
+/* Features from bPINSupport */
+#define CCID_CLASS_PIN_VERIFY 0x01
+#define CCID_CLASS_PIN_MODIFY 0x02
+
+/* See CCID specs ch. 4.2.1 */
+#define CCID_ICC_PRESENT_ACTIVE 0x00 /* 00 0000 00 */
+#define CCID_ICC_PRESENT_INACTIVE 0x01 /* 00 0000 01 */
+#define CCID_ICC_ABSENT 0x02 /* 00 0000 10 */
+#define CCID_ICC_STATUS_MASK 0x03 /* 00 0000 11 */
+
+#define CCID_COMMAND_FAILED 0x40 /* 01 0000 00 */
+#define CCID_TIME_EXTENSION 0x80 /* 10 0000 00 */
+
+/* bInterfaceProtocol for ICCD */
+#define PROTOCOL_CCID 0 /* plain CCID */
+#define PROTOCOL_ICCD_A 1 /* ICCD Version A */
+#define PROTOCOL_ICCD_B 2 /* ICCD Version B */
+
+/* Product identification for special treatments */
+#define GEMPC433 0x08E64433
+#define GEMPCKEY 0x08E63438
+#define GEMPCTWIN 0x08E63437
+#define GEMPCPINPAD 0x08E63478
+#define GEMCORESIMPRO 0x08E63480
+#define GEMCORESIMPRO2 0x08E60000 /* Does NOT match a real VID/PID as new firmware release exposes same VID/PID */
+#define GEMCOREPOSPRO 0x08E63479
+#define GEMALTOPROXDU 0x08E65503
+#define GEMALTOPROXSU 0x08E65504
+#define GEMALTO_EZIO_CBP 0x08E634C3
+#define CARDMAN3121 0x076B3021
+#define LTC31 0x07830003
+#define SCR331DI 0x04E65111
+#define SCR331DINTTCOM 0x04E65120
+#define SDI010 0x04E65121
+#define CHERRYXX33 0x046A0005
+#define CHERRYST2000 0x046A003E
+#define OZ776 0x0B977762
+#define OZ776_7772 0x0B977772
+#define SPR532 0x04E6E003
+#define MYSMARTPAD 0x09BE0002
+#define CHERRYXX44 0x046a0010
+#define CL1356D 0x0B810200
+#define REINER_SCT 0x0C4B0300
+#define SEG 0x08E68000
+#define BLUDRIVEII_CCID 0x1B0E1078
+#define DELLSCRK 0x413C2101
+#define DELLSK 0x413C2100
+#define KOBIL_TRIBANK 0x0D463010
+#define KOBIL_MIDENTITY_VISUAL 0x0D460D46
+#define VEGAALPHA 0x09820008
+#define HPSMARTCARDKEYBOARD 0x03F01024
+#define HP_CCIDSMARTCARDKEYBOARD 0x03F00036
+#define KOBIL_IDTOKEN 0x0D46301D
+#define FUJITSUSMARTKEYB 0x0BF81017
+
+#define VENDOR_GEMALTO 0x08E6
+#define GET_VENDOR(readerID) ((readerID >> 16) & 0xFFFF)
+
+/*
+ * The O2Micro OZ776S reader has a wrong USB descriptor
+ * The extra[] field is associated with the last endpoint instead of the
+ * main USB descriptor
+ */
+#define O2MICRO_OZ776_PATCH
+
+/* Escape sequence codes */
+#define ESC_GEMPC_SET_ISO_MODE 1
+#define ESC_GEMPC_SET_APDU_MODE 2
+
+/*
+ * Possible values :
+ * 3 -> 1.8V, 3V, 5V
+ * 2 -> 3V, 5V
+ * 1 -> 5V only
+ * 0 -> automatic (selection made by the reader)
+ */
+/*
+ * To be safe we default to 5V
+ * otherwise we would have to parse the ATR and get the value of TAi (i>2) when
+ * in T=15
+ */
+#define VOLTAGE_AUTO 0
+#define VOLTAGE_5V 1
+#define VOLTAGE_3V 2
+#define VOLTAGE_1_8V 3
+
+int ccid_open_hack_pre(unsigned int reader_index);
+int ccid_open_hack_post(unsigned int reader_index);
+void ccid_error(int error, const char *file, int line, const char *function);
+_ccid_descriptor *get_ccid_descriptor(unsigned int reader_index);
+
+/* convert a 4 byte integer in USB format into an int */
+#define dw2i(a, x) (unsigned int)((((((a[x+3] << 8) + a[x+2]) << 8) + a[x+1]) << 8) + a[x])
+
+/* all the data rates specified by ISO 7816-3 Fi/Di tables */
+#define ISO_DATA_RATES 10753, 14337, 15625, 17204, \
+ 20833, 21505, 23438, 25806, 28674, \
+ 31250, 32258, 34409, 39063, 41667, \
+ 43011, 46875, 52083, 53763, 57348, \
+ 62500, 64516, 68817, 71685, 78125, \
+ 83333, 86022, 93750, 104167, 107527, \
+ 114695, 125000, 129032, 143369, 156250, \
+ 166667, 172043, 215054, 229391, 250000, \
+ 344086
+
+/* data rates supported by the secondary slots on the GemCore Pos Pro & SIM Pro */
+#define GEMPLUS_CUSTOM_DATA_RATES 10753, 21505, 43011, 125000
+
+/* data rates for GemCore SIM Pro 2 */
+#define SIMPRO2_ISO_DATA_RATES 8709, 10322, 12403, 12500, \
+ 12903, 17204, 18750, 20645, 24806, \
+ 25000, 25806, 28125, 30967, 34408, \
+ 37500, 41290, 46875, 49612, 50000, \
+ 51612, 56250, 62500, 64516, 68817, \
+ 74418, 75000, 82580, 86021, 93750, \
+ 99224, 100000, 103225, 112500, 124031, \
+ 125000, 137634, 150000, 154838, 165161, \
+ 172043, 187500, 198449, 200000, 206451, \
+ 258064, 275268, 300000, 396899, 400000, \
+ 412903, 550537, 600000, 825806
+
+/* Structure returned by Gemalto readers for the CCID Escape command 0x6A */
+struct GEMALTO_FIRMWARE_FEATURES
+{
+ unsigned char bLogicalLCDLineNumber; /* Logical number of LCD lines */
+ unsigned char bLogicalLCDRowNumber; /* Logical number of characters per LCD line */
+ unsigned char bLcdInfo; /* b0 indicates if scrolling is available */
+ unsigned char bEntryValidationCondition; /* See PIN_PROPERTIES */
+
+ /* Here come the PC/SC bit features to report */
+ unsigned char VerifyPinStart:1;
+ unsigned char VerifyPinFinish:1;
+ unsigned char ModifyPinStart:1;
+ unsigned char ModifyPinFinish:1;
+ unsigned char GetKeyPressed:1;
+ unsigned char VerifyPinDirect:1;
+ unsigned char ModifyPinDirect:1;
+ unsigned char Abort:1;
+
+ unsigned char GetKey:1;
+ unsigned char WriteDisplay:1;
+ unsigned char SetSpeMessage:1;
+ unsigned char RFUb1:5;
+
+ unsigned char RFUb2[2];
+
+ /* Additional flags */
+ unsigned char bTimeOut2:1;
+ unsigned char bListSupportedLanguages:1; /* Reader is able to indicate
+ the list of supported languages through CCID-ESC 0x6B */
+ unsigned char bNumberMessageFix:1; /* Reader handles correctly shifts
+ made by bNumberMessage in PIN modification data structure */
+ unsigned char bPPDUSupportOverXferBlock:1; /* Reader supports PPDU over
+ PC_to_RDR_XferBlock command */
+ unsigned char bPPDUSupportOverEscape:1; /* Reader supports PPDU over
+ PC_to_RDR_Escape command with abData[0]=0xFF */
+ unsigned char RFUb3:3;
+
+ unsigned char RFUb4[3];
+
+ unsigned char VersionNumber; /* ?? */
+ unsigned char MinimumPINSize; /* for Verify and Modify */
+ unsigned char MaximumPINSize;
+
+ /* Miscellaneous reader features */
+ unsigned char Firewall:1;
+ unsigned char RFUb5:7;
+
+ /* The following fields, FirewalledCommand_SW1 and
+ * FirewalledCommand_SW2 are only valid if Firewall=1
+ * These fields give the SW1 SW2 value used by the reader to
+ * indicate a command has been firewalled */
+ unsigned char FirewalledCommand_SW1;
+ unsigned char FirewalledCommand_SW2;
+ unsigned char RFUb6[3];
+};
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h
new file mode 100644
index 0000000..6276154
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h
@@ -0,0 +1,63 @@
+/*
+ ccid_ifdhandler.h: non-generic ifdhandler functions
+ Copyright (C) 2004-2010 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: ccid_ifdhandler.h 6876 2014-03-23 12:00:57Z rousseau $
+ */
+
+#ifndef _ccid_ifd_handler_h_
+#define _ccid_ifd_handler_h_
+
+#define IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE SCARD_CTL_CODE(1)
+
+#define CLASS2_IOCTL_MAGIC 0x330000
+#define IOCTL_FEATURE_VERIFY_PIN_DIRECT \
+ SCARD_CTL_CODE(FEATURE_VERIFY_PIN_DIRECT + CLASS2_IOCTL_MAGIC)
+#define IOCTL_FEATURE_MODIFY_PIN_DIRECT \
+ SCARD_CTL_CODE(FEATURE_MODIFY_PIN_DIRECT + CLASS2_IOCTL_MAGIC)
+#define IOCTL_FEATURE_MCT_READER_DIRECT \
+ SCARD_CTL_CODE(FEATURE_MCT_READER_DIRECT + CLASS2_IOCTL_MAGIC)
+#define IOCTL_FEATURE_IFD_PIN_PROPERTIES \
+ SCARD_CTL_CODE(FEATURE_IFD_PIN_PROPERTIES + CLASS2_IOCTL_MAGIC)
+#define IOCTL_FEATURE_GET_TLV_PROPERTIES \
+ SCARD_CTL_CODE(FEATURE_GET_TLV_PROPERTIES + CLASS2_IOCTL_MAGIC)
+
+#define DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED 1
+#define DRIVER_OPTION_GEMPC_TWIN_KEY_APDU 2
+#define DRIVER_OPTION_USE_BOGUS_FIRMWARE 4
+#define DRIVER_OPTION_RESET_ON_CLOSE 8
+#define DRIVER_OPTION_DISABLE_PIN_RETRIES (1 << 6)
+
+extern int DriverOptions;
+
+/*
+ * Maximum number of CCID readers supported simultaneously
+ *
+ * The maximum number of readers is also limited in pcsc-lite (16 by default)
+ * see the definition of PCSCLITE_MAX_READERS_CONTEXTS in src/PCSC/pcsclite.h
+ */
+#define CCID_DRIVER_MAX_READERS 16
+
+/*
+ * CCID driver specific functions
+ */
+CcidDesc *get_ccid_slot(unsigned int reader_index);
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c
new file mode 100644
index 0000000..ac888c1
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c
@@ -0,0 +1,470 @@
+/*
+ ccid_uefi.c: USB access routines using the UEFI USB protocol
+ Copyright (C) 2014 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: ccid_usb.c 6890 2014-04-24 13:51:03Z rousseau $
+ */
+
+#include <Protocol/UsbIo.h>
+#include <Library/UefiLib.h>
+#include <CcidDriver.h>
+
+#include <ifdhandler.h>
+
+#include "config.h"
+#include "misc.h"
+#include "ccid.h"
+#include "debug.h"
+#include "defs.h"
+#include "utils.h"
+#include "ccid_ifdhandler.h"
+
+
+/* write timeout
+ * we don't have to wait a long time since the card was doing nothing */
+#define USB_WRITE_TIMEOUT (5 * 1000) /* 5 seconds timeout */
+
+/*
+ * Proprietary USB Class (0xFF) are (or are not) accepted
+ * A proprietary class is used for devices released before the final CCID
+ * specifications were ready.
+ * We should not have problems with non CCID devices because the
+ * Manufacturer and Product ID are also used to identify the device */
+#define ALLOW_PROPRIETARY_CLASS
+
+#define BUS_DEVICE_STRSIZE 32
+
+#define CCID_INTERRUPT_SIZE 8
+
+typedef struct
+{
+ EFI_USB_INTERFACE_DESCRIPTOR *dev_handle;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ uint8_t bus_number;
+ uint8_t device_address;
+
+ /*
+ * Endpoints
+ */
+ EFI_USB_ENDPOINT_DESCRIPTOR bulk_in;
+ EFI_USB_ENDPOINT_DESCRIPTOR bulk_out;
+ EFI_USB_ENDPOINT_DESCRIPTOR interrupt;
+
+ /* Number of slots using the same device */
+ int real_nb_opened_slots;
+ int *nb_opened_slots;
+
+ /*
+ * CCID infos common to USB and serial
+ */
+ _ccid_descriptor ccid;
+
+} _usbDevice;
+
+/* The _usbDevice structure must be defined before including ccid_usb.h */
+#include "ccid_uefi.h"
+
+/* ne need to initialize to 0 since it is static */
+static _usbDevice usbDevice[CCID_DRIVER_MAX_READERS];
+
+//
+// Send general device request timeout.
+//
+// The USB Specification 2.0, section 11.24.1 recommends a value of
+// 50 milliseconds. We use a value of 500 milliseconds to work
+// around slower hubs and devices.
+//
+#define USB_GENERAL_DEVICE_REQUEST_TIMEOUT 500
+
+
+/*****************************************************************************
+ *
+ * OpenUEFI
+ *
+ ****************************************************************************/
+status_t OpenUEFI(unsigned int reader_index, DWORD Channel)
+{
+ int return_value = STATUS_UNSUCCESSFUL;
+ USB_CCID_DEV *UsbCcidDevice = (USB_CCID_DEV *)Channel;
+ int index;
+ UINT8 EndpointNumber;
+ EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ unsigned char * device_descriptor, *ccid_descriptor;
+ EFI_USB_DEVICE_REQUEST DevReq;
+ UINT32 Status_uint;
+
+ DEBUG_COMM3("Reader index: %X, Channel: %p", reader_index, UsbCcidDevice);
+
+ UsbIo = UsbCcidDevice->UsbIo;
+ usbDevice[reader_index].UsbIo = UsbIo;
+
+ //
+ // Get the Device Path Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ UsbCcidDevice->ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UsbCcidDevice->DevicePath,
+ UsbCcidDevice->DriverBindingHandle,
+ UsbCcidDevice->ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status))
+ {
+ Log2(PCSC_LOG_DEBUG, "OpenProtocol %d", Status);
+ goto ErrorExit;
+ }
+
+ /* Get Device descriptor */
+ Status = UsbIo->UsbGetDeviceDescriptor(UsbIo,
+ &UsbCcidDevice->DeviceDescriptor);
+ if (EFI_ERROR (Status))
+ {
+ Log2(PCSC_LOG_DEBUG, "UsbGetDeviceDescriptor %d", Status);
+ goto ErrorExit;
+ }
+
+ /* Get Config descriptor */
+ Status = UsbIo->UsbGetConfigDescriptor(UsbIo,
+ &UsbCcidDevice->ConfigDescriptor);
+ if (EFI_ERROR (Status))
+ {
+ Log2(PCSC_LOG_DEBUG, "UsbGetConfigDescriptor %d", Status);
+ goto ErrorExit;
+ }
+
+ //
+ // Get interface & endpoint descriptor
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor(UsbIo,
+ &UsbCcidDevice->InterfaceDescriptor);
+ if (EFI_ERROR (Status))
+ {
+ Log2(PCSC_LOG_DEBUG, "UsbGetInterfaceDescriptor %d", Status);
+ goto ErrorExit;
+ }
+
+ EndpointNumber = UsbCcidDevice->InterfaceDescriptor.NumEndpoints;
+
+ /* Get Endpoints values*/
+ for (index = 0; index < EndpointNumber; index++)
+ {
+ UsbIo->UsbGetEndpointDescriptor (UsbIo, index, &EndpointDescriptor);
+
+ if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT)
+ CopyMem(&usbDevice[reader_index].interrupt, &EndpointDescriptor, sizeof(EndpointDescriptor));
+
+ if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_BULK)
+ {
+ if (EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN)
+ CopyMem(&usbDevice[reader_index].bulk_in, &EndpointDescriptor, sizeof(EndpointDescriptor));
+ else
+ CopyMem(&usbDevice[reader_index].bulk_out, &EndpointDescriptor, sizeof(EndpointDescriptor));
+ }
+ }
+
+ device_descriptor = AllocateZeroPool(UsbCcidDevice->ConfigDescriptor.TotalLength);
+ ASSERT(device_descriptor != NULL);
+
+ /* Get USB CCID Descriptor */
+ DevReq.RequestType = USB_DEV_GET_DESCRIPTOR_REQ_TYPE;
+ DevReq.Request = USB_REQ_GET_DESCRIPTOR;
+ DevReq.Value = (UINT16)((USB_DESC_TYPE_CONFIG << 8) | 0 /* Index */);
+ DevReq.Index = UsbCcidDevice->InterfaceDescriptor.InterfaceNumber;
+ DevReq.Length = UsbCcidDevice->ConfigDescriptor.TotalLength;
+
+ Status = UsbIo->UsbControlTransfer(UsbIo,
+ &DevReq,
+ EfiUsbDataIn,
+ USB_GENERAL_DEVICE_REQUEST_TIMEOUT,
+ device_descriptor,
+ UsbCcidDevice->ConfigDescriptor.TotalLength,
+ &Status_uint
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeExit;
+ }
+
+ /* find the CCID descriptor */
+ index = 0;
+ while (device_descriptor[index] != 0x36 && index < UsbCcidDevice->ConfigDescriptor.TotalLength)
+ {
+ /* bug in descriptor? */
+ if (0 == device_descriptor[index])
+ break;
+
+ index += device_descriptor[index];
+ }
+
+ if (device_descriptor[index] != 0x36 && device_descriptor[index+1] != 0x21)
+ {
+ Print(L"CCID descriptor not found\n");
+ goto FreeExit;
+ }
+
+ /* move to the first byte of the CCID descriptor */
+ ccid_descriptor = device_descriptor + index;
+
+ /* store device information */
+ usbDevice[reader_index].real_nb_opened_slots = 1;
+ usbDevice[reader_index].nb_opened_slots = &usbDevice[reader_index].real_nb_opened_slots;
+
+ /* CCID common informations */
+ usbDevice[reader_index].ccid.real_bSeq = 0;
+ usbDevice[reader_index].ccid.pbSeq = &usbDevice[reader_index].ccid.real_bSeq;
+ usbDevice[reader_index].ccid.readerID =
+ (UsbCcidDevice->DeviceDescriptor.IdVendor << 16)
+ + UsbCcidDevice->DeviceDescriptor.IdProduct;
+ usbDevice[reader_index].ccid.dwFeatures = dw2i(ccid_descriptor, 40);
+ usbDevice[reader_index].ccid.wLcdLayout =
+ (ccid_descriptor[51] << 8) + ccid_descriptor[50];
+ usbDevice[reader_index].ccid.bPINSupport = ccid_descriptor[52];
+ usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = dw2i(ccid_descriptor, 44);
+ usbDevice[reader_index].ccid.dwMaxIFSD = dw2i(ccid_descriptor, 28);
+ usbDevice[reader_index].ccid.dwDefaultClock = dw2i(ccid_descriptor, 10);
+ usbDevice[reader_index].ccid.dwMaxDataRate = dw2i(ccid_descriptor, 23);
+ usbDevice[reader_index].ccid.bMaxSlotIndex = ccid_descriptor[4];
+ usbDevice[reader_index].ccid.bCurrentSlotIndex = 0;
+ usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT;
+#if 0
+ if (ccid_descriptor[27])
+ usbDevice[reader_index].ccid.arrayOfSupportedDataRates = get_data_rates(reader_index, config_desc, num);
+ else
+ {
+ usbDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL;
+ DEBUG_INFO1("bNumDataRatesSupported is 0");
+ }
+#endif
+ usbDevice[reader_index].ccid.bInterfaceProtocol = UsbCcidDevice->InterfaceDescriptor.InterfaceProtocol;
+ usbDevice[reader_index].ccid.bNumEndpoints = UsbCcidDevice->InterfaceDescriptor.NumEndpoints;
+ usbDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT;
+ usbDevice[reader_index].ccid.bVoltageSupport = ccid_descriptor[5];
+ usbDevice[reader_index].ccid.sIFD_serial_number = NULL;
+ usbDevice[reader_index].ccid.gemalto_firmware_features = NULL;
+ usbDevice[reader_index].ccid.zlp = FALSE;
+ usbDevice[reader_index].ccid.sIFD_iManufacturer = NULL;
+ usbDevice[reader_index].ccid.IFD_bcdDevice = UsbCcidDevice->DeviceDescriptor.BcdDevice;
+
+ /* no error */
+ return_value = STATUS_SUCCESS;
+
+FreeExit:
+ FreePool(device_descriptor);
+
+ErrorExit:
+ return return_value;
+} /* OpenUEFI */
+
+
+/*****************************************************************************
+ *
+ * OpenUEFIByName
+ *
+ ****************************************************************************/
+status_t OpenUEFIByName(unsigned int reader_index, /*@null@*/ char *device)
+{
+ return STATUS_UNSUCCESSFUL;
+} /* OpenUEFIByName */
+
+
+/*****************************************************************************
+ *
+ * WriteUEFI
+ *
+ ****************************************************************************/
+status_t WriteUEFI(unsigned int reader_index, unsigned int length,
+ unsigned char *buffer)
+{
+ UINT32 TransStatus;
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo = usbDevice[reader_index].UsbIo;
+ UINTN DataLength;
+
+ DEBUG_XXD(">", buffer, length);
+
+ DataLength = length;
+ Status = UsbIo->UsbBulkTransfer(UsbIo,
+ usbDevice[reader_index].bulk_out.EndpointAddress, buffer, &DataLength,
+ USB_WRITE_TIMEOUT, &TransStatus);
+
+ if (EFI_ERROR (Status))
+ {
+ Print(L"UsbBulkTransfer(write) failed\n");
+ return STATUS_COMM_ERROR;
+ }
+
+ return STATUS_SUCCESS;
+} /* WriteUEFI */
+
+
+/*****************************************************************************
+ *
+ * ReadUEFI
+ *
+ ****************************************************************************/
+status_t ReadUEFI(unsigned int reader_index, unsigned int * length,
+ unsigned char *buffer)
+{
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ int duplicate_frame = 0;
+ UINT32 TransStatus;
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo = usbDevice[reader_index].UsbIo;
+ UINTN DataLength;
+
+read_again:
+ DataLength = *length;
+ Status = UsbIo->UsbBulkTransfer(UsbIo,
+ usbDevice[reader_index].bulk_in.EndpointAddress, buffer, &DataLength,
+ usbDevice[reader_index].ccid.readTimeout, &TransStatus);
+
+ if (EFI_ERROR (Status))
+ {
+ *length = 0;
+ Print(L"UsbBulkTransfer(read) failed\n");
+
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ *length = DataLength;
+
+ DEBUG_XXD("<", buffer, *length);
+
+#define BSEQ_OFFSET 6
+ if ((*length >= BSEQ_OFFSET)
+ && (buffer[BSEQ_OFFSET] < *ccid_descriptor->pbSeq -1))
+ {
+ duplicate_frame++;
+ if (duplicate_frame > 10)
+ {
+ DEBUG_CRITICAL("Too many duplicate frame detected");
+ return STATUS_UNSUCCESSFUL;
+ }
+ DEBUG_INFO1("Duplicate frame detected");
+ goto read_again;
+ }
+
+ return STATUS_SUCCESS;
+} /* ReadUEFI */
+
+
+/*****************************************************************************
+ *
+ * ControlUSB
+ *
+ ****************************************************************************/
+int ControlUSB(int reader_index, int requesttype, int request, int value,
+ unsigned char *bytes, unsigned int size)
+{
+ Print(L"ControlUEFI not implemented\n");
+ return STATUS_COMM_ERROR;
+} /* ControlUSB */
+
+
+/*****************************************************************************
+ *
+ * CloseUEFI
+ *
+ ****************************************************************************/
+status_t CloseUEFI(unsigned int reader_index)
+{
+ /* device not opened */
+ if (usbDevice[reader_index].dev_handle == NULL)
+ return STATUS_UNSUCCESSFUL;
+
+ Log0(PCSC_LOG_DEBUG);
+ DEBUG_COMM3("Closing USB device: %d/%d",
+ usbDevice[reader_index].bus_number,
+ usbDevice[reader_index].device_address);
+
+ /* one slot closed */
+ (*usbDevice[reader_index].nb_opened_slots)--;
+
+ /* release the allocated ressources for the last slot only */
+ if (0 == *usbDevice[reader_index].nb_opened_slots)
+ {
+ DEBUG_COMM("Last slot closed. Release resources");
+
+ if (usbDevice[reader_index].ccid.gemalto_firmware_features)
+ free(usbDevice[reader_index].ccid.gemalto_firmware_features);
+
+ if (usbDevice[reader_index].ccid.sIFD_serial_number)
+ free(usbDevice[reader_index].ccid.sIFD_serial_number);
+
+ if (usbDevice[reader_index].ccid.sIFD_iManufacturer)
+ free(usbDevice[reader_index].ccid.sIFD_iManufacturer);
+
+ if (usbDevice[reader_index].ccid.arrayOfSupportedDataRates)
+ free(usbDevice[reader_index].ccid.arrayOfSupportedDataRates);
+ }
+
+ /* mark the resource unused */
+ usbDevice[reader_index].dev_handle = NULL;
+
+ return STATUS_SUCCESS;
+} /* CloseUEFI */
+
+
+/*****************************************************************************
+ *
+ * get_ccid_descriptor
+ *
+ ****************************************************************************/
+_ccid_descriptor *get_ccid_descriptor(unsigned int reader_index)
+{
+ return &usbDevice[reader_index].ccid;
+} /* get_ccid_descriptor */
+
+
+/*****************************************************************************
+ *
+ * get_usb_device
+ *
+ ****************************************************************************/
+void duplicate_usb_device(unsigned int reader_index,
+ unsigned int new_reader_index)
+{
+ usbDevice[new_reader_index] = usbDevice[reader_index];
+} /* get_usb_device */
+
+/*****************************************************************************
+ *
+ * InterruptRead
+ *
+ ****************************************************************************/
+int InterruptRead(int reader_index, int timeout /* in ms */)
+{
+ int return_value = IFD_SUCCESS;
+ return return_value;
+} /* InterruptRead */
+
+
+/*****************************************************************************
+ *
+ * Stop the async loop
+ *
+ ****************************************************************************/
+void InterruptStop(int reader_index)
+{
+} /* InterruptStop */
+
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h
new file mode 100644
index 0000000..31d32f0
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h
@@ -0,0 +1,46 @@
+/*
+ ccid_uefi.h: USB access routines using the UEFI USB protocol
+ Copyright (C) 2014 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: ccid_uefi.h 5473 2011-01-04 09:52:26Z rousseau $
+ */
+
+#ifndef __CCID_UEF_H__
+#define __CCID_UEFI_H__
+status_t OpenUEFI(unsigned int reader_index, DWORD channel);
+
+status_t OpenUEFIByName(unsigned int reader_index, /*@null@*/ char *device);
+
+status_t WriteUEFI(unsigned int reader_index, unsigned int length,
+ unsigned char *Buffer);
+
+status_t ReadUEFI(unsigned int reader_index, unsigned int *length,
+ /*@out@*/ unsigned char *Buffer);
+
+status_t CloseUEFI(unsigned int reader_index);
+
+int ControlUSB(int reader_index, int requesttype, int request, int value,
+ unsigned char *bytes, unsigned int size);
+
+void duplicate_usb_device(unsigned int reader_index,
+ unsigned int new_reader_index);
+
+int InterruptRead(int reader_index, int timeout);
+
+#endif
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/commands.c b/MdeModulePkg/Library/SmartCardReader/libccid/commands.c
new file mode 100644
index 0000000..006f546
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/commands.c
@@ -0,0 +1,2294 @@
+/*
+ commands.c: Commands sent to the card
+ Copyright (C) 2003-2010 Ludovic Rousseau
+ Copyright (C) 2005 Martin Paljak
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: commands.c 6975 2014-09-04 11:33:05Z rousseau $
+ */
+
+#include <config.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <pcsclite.h>
+#include <ifdhandler.h>
+#include <reader.h>
+
+#include "misc.h"
+#include "commands.h"
+#include "openct/proto-t1.h"
+#include "ccid.h"
+#include "defs.h"
+#include "ccid_ifdhandler.h"
+#include "debug.h"
+
+/* All the pinpad readers I used are more or less bogus
+ * I use code to change the user command and make the firmware happy */
+#define BOGUS_PINPAD_FIRMWARE
+
+/* The firmware of SCM readers reports dwMaxCCIDMessageLength = 263
+ * instead of 270 so this prevents from sending a full length APDU
+ * of 260 bytes since the driver check this value */
+#define BOGUS_SCM_FIRMWARE_FOR_dwMaxCCIDMessageLength
+
+#define max( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifndef BSWAP_16
+#define BSWAP_8(x) ((x) & 0xff)
+#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))
+#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
+#endif
+
+#define CHECK_STATUS(res) \
+ if (STATUS_NO_SUCH_DEVICE == res) \
+ return IFD_NO_SUCH_DEVICE; \
+ if (STATUS_SUCCESS != res) \
+ return IFD_COMMUNICATION_ERROR;
+
+/* internal functions */
+static RESPONSECODE CmdXfrBlockAPDU_extended(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[]);
+
+static RESPONSECODE CmdXfrBlockTPDU_T0(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[]);
+
+static RESPONSECODE CmdXfrBlockCHAR_T0(unsigned int reader_index, unsigned int
+ tx_length, unsigned char tx_buffer[], unsigned int *rx_length, unsigned
+ char rx_buffer[]);
+
+static RESPONSECODE CmdXfrBlockTPDU_T1(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[]);
+
+static void i2dw(int value, unsigned char *buffer);
+static unsigned int bei2i(unsigned char *buffer);
+
+
+/*****************************************************************************
+ *
+ * CmdPowerOn
+ *
+ ****************************************************************************/
+RESPONSECODE CmdPowerOn(unsigned int reader_index, unsigned int * nlength,
+ unsigned char buffer[], int voltage)
+{
+ unsigned char cmd[10];
+ status_t res;
+ int length, count = 1;
+ unsigned int atr_len;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+#ifndef TWIN_SERIAL
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+
+ /* first power off to reset the ICC state machine */
+ r = CmdPowerOff(reader_index);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* wait for ready */
+ r = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* Power On */
+ r = ControlUSB(reader_index, 0xA1, 0x62, 0, buffer, *nlength);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power On failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ *nlength = r;
+
+ return IFD_SUCCESS;
+ }
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char tmp[MAX_ATR_SIZE+1];
+
+ /* first power off to reset the ICC state machine */
+ r = CmdPowerOff(reader_index);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* Power On */
+ r = ControlUSB(reader_index, 0x21, 0x62, 1, NULL, 0);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power On failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* Data Block */
+ r = ControlUSB(reader_index, 0xA1, 0x6F, 0, tmp, sizeof(tmp));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (tmp[0] != 0x00)
+ {
+ DEBUG_CRITICAL2("bResponseType: 0x%02X", tmp[0]);
+
+ /* Status Information? */
+ if (0x40 == tmp[0])
+ ccid_error(tmp[2], __FILE__, __LINE__, __FUNCTION__);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ DEBUG_INFO_XXD("Data Block: ", tmp, r);
+ if ((int)*nlength > r-1)
+ *nlength = r-1;
+ memcpy(buffer, tmp+1, *nlength);
+
+ return IFD_SUCCESS;
+ }
+#endif
+
+ /* store length of buffer[] */
+ length = *nlength;
+
+ if (ccid_descriptor->dwFeatures & CCID_CLASS_AUTO_VOLTAGE)
+ voltage = 0; /* automatic voltage selection */
+ else
+ {
+ int bVoltageSupport = ccid_descriptor->bVoltageSupport;
+
+ if ((1 == voltage) && !(bVoltageSupport & 1))
+ {
+ DEBUG_INFO1("5V requested but not support by reader");
+ voltage = 2; /* 3V */
+ }
+
+ if ((2 == voltage) && !(bVoltageSupport & 2))
+ {
+ DEBUG_INFO1("3V requested but not support by reader");
+ voltage = 3; /* 1.8V */
+ }
+
+ if ((3 == voltage) && !(bVoltageSupport & 4))
+ {
+ DEBUG_INFO1("1.8V requested but not support by reader");
+ voltage = 0; /* auto */
+ }
+ }
+
+again:
+ cmd[0] = 0x62; /* IccPowerOn */
+ cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = voltage;
+ cmd[8] = cmd[9] = 0; /* RFU */
+
+ res = WritePort(reader_index, sizeof(cmd), cmd);
+ CHECK_STATUS(res)
+
+ /* reset available buffer size */
+ /* needed if we go back after a switch to ISO mode */
+ *nlength = length;
+
+ res = ReadPort(reader_index, nlength, buffer);
+ CHECK_STATUS(res)
+
+ if (*nlength < STATUS_OFFSET+1)
+ {
+ DEBUG_CRITICAL2("Not enough data received: %d bytes", *nlength);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
+ {
+ ccid_error(buffer[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
+
+ if (0xBB == buffer[ERROR_OFFSET] && /* Protocol error in EMV mode */
+ ((GEMPC433 == ccid_descriptor->readerID)
+ || (CHERRYXX33 == ccid_descriptor->readerID)))
+ {
+ unsigned char cmd_tmp[] = {0x1F, 0x01};
+ unsigned char res_tmp[1];
+ unsigned int res_length = sizeof(res_tmp);
+
+ if ((return_value = CmdEscape(reader_index, cmd_tmp,
+ sizeof(cmd_tmp), res_tmp, &res_length, 0)) != IFD_SUCCESS)
+ return return_value;
+
+ /* avoid looping if we can't switch mode */
+ if (count--)
+ goto again;
+ else
+ DEBUG_CRITICAL("Can't set reader in ISO mode");
+ }
+
+ /* continue with 3 volts and 5 volts */
+ if (voltage > 1)
+ {
+#ifndef NO_LOG
+ const char *voltage_code[] = { "auto", "5V", "3V", "1.8V" };
+#endif
+
+ DEBUG_INFO3("Power up with %s failed. Try with %s.",
+ voltage_code[voltage], voltage_code[voltage-1]);
+ voltage--;
+ goto again;
+ }
+
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* extract the ATR */
+ atr_len = dw2i(buffer, 1); /* ATR length */
+ if (atr_len > *nlength)
+ atr_len = *nlength;
+ else
+ *nlength = atr_len;
+
+ memmove(buffer, buffer+10, atr_len);
+
+ return return_value;
+} /* CmdPowerOn */
+
+
+/*****************************************************************************
+ *
+ * SecurePINVerify
+ *
+ ****************************************************************************/
+RESPONSECODE SecurePINVerify(unsigned int reader_index,
+ unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength)
+{
+ unsigned char cmd[11+14+TxLength];
+ unsigned int a, b;
+ PIN_VERIFY_STRUCTURE *pvs;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ int old_read_timeout;
+ RESPONSECODE ret;
+ status_t res;
+
+ pvs = (PIN_VERIFY_STRUCTURE *)TxBuffer;
+ cmd[0] = 0x69; /* Secure */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = 0; /* bBWI */
+ cmd[8] = 0; /* wLevelParameter */
+ cmd[9] = 0;
+ cmd[10] = 0; /* bPINOperation: PIN Verification */
+
+ if (TxLength < 19+4 /* 4 = APDU size */) /* command too short? */
+ {
+ DEBUG_INFO3("Command too short: %d < %d", TxLength, 19+4);
+ return IFD_NOT_SUPPORTED;
+ }
+
+ /* On little endian machines we are all set. */
+ /* If on big endian machine and caller is using host byte order */
+ if ((pvs->ulDataLength + 19 == TxLength) &&
+ (bei2i((unsigned char*)(&pvs->ulDataLength)) == pvs->ulDataLength))
+ {
+ DEBUG_INFO1("Reversing order from big to little endian");
+ /* If ulDataLength is big endian, assume others are too */
+ /* reverse the byte order for 3 fields */
+ pvs->wPINMaxExtraDigit = BSWAP_16(pvs->wPINMaxExtraDigit);
+ pvs->wLangId = BSWAP_16(pvs->wLangId);
+ pvs->ulDataLength = BSWAP_32(pvs->ulDataLength);
+ }
+ /* At this point we now have the above 3 variables in little endian */
+
+ if (dw2i(TxBuffer, 15) + 19 != TxLength) /* ulDataLength field coherency */
+ {
+ DEBUG_INFO3("Wrong lengths: %d %d", dw2i(TxBuffer, 15) + 19, TxLength);
+ return IFD_NOT_SUPPORTED;
+ }
+
+ /* make sure bEntryValidationCondition is valid
+ * The Cherry XX44 reader crashes with a wrong value */
+ if ((0x00 == TxBuffer[7]) || (TxBuffer[7] > 0x07))
+ {
+ DEBUG_INFO2("Correct bEntryValidationCondition (was 0x%02X)",
+ TxBuffer[7]);
+ TxBuffer[7] = 0x02;
+ }
+
+#ifdef BOGUS_PINPAD_FIRMWARE
+ /* bug circumvention for the GemPC Pinpad */
+ if ((GEMPCPINPAD == ccid_descriptor->readerID)
+ || (VEGAALPHA == ccid_descriptor->readerID))
+ {
+ /* the firmware reject the cases: 00h No string and FFh default
+ * CCID message. The only value supported is 01h (display 1 message) */
+ if (0x01 != TxBuffer[8])
+ {
+ DEBUG_INFO2("Correct bNumberMessage for GemPC Pinpad (was %d)",
+ TxBuffer[8]);
+ TxBuffer[8] = 0x01;
+ }
+
+ /* The reader does not support, and actively reject, "max size reached"
+ * and "timeout occured" validation conditions */
+ if (0x02 != TxBuffer[7])
+ {
+ DEBUG_INFO2("Correct bEntryValidationCondition for GemPC Pinpad (was %d)",
+ TxBuffer[7]);
+ TxBuffer[7] = 0x02; /* validation key pressed */
+ }
+
+ }
+
+ if ((DELLSCRK == ccid_descriptor->readerID)
+ || (DELLSK == ccid_descriptor->readerID))
+ {
+ /* the firmware rejects the cases: 01h-FEh and FFh default
+ * CCID message. The only value supported is 00h (no message) */
+ if (0x00 != TxBuffer[8])
+ {
+ DEBUG_INFO2("Correct bNumberMessage for Dell keyboard (was %d)",
+ TxBuffer[8]);
+ TxBuffer[8] = 0x00;
+ }
+
+ /* avoid the command rejection because the Enter key is still
+ * pressed. Wait a bit for the key to be released */
+ (void)usleep(250*1000);
+ }
+
+ if (DELLSK == ccid_descriptor->readerID)
+ {
+ /* the 2 bytes of wPINMaxExtraDigit are reversed */
+ int tmp;
+
+ tmp = TxBuffer[6];
+ TxBuffer[6] = TxBuffer[5];
+ TxBuffer[5] = tmp;
+ DEBUG_INFO1("Correcting wPINMaxExtraDigit for Dell keyboard");
+ }
+#endif
+
+ /* T=1 Protocol Management for a TPDU reader */
+ if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
+ && (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
+ {
+ ct_buf_t sbuf;
+ unsigned char sdata[T1_BUFFER_SIZE];
+
+ /* Initialize send buffer with the APDU */
+ ct_buf_set(&sbuf,
+ (void *)(TxBuffer + offsetof(PIN_VERIFY_STRUCTURE, abData)),
+ TxLength - offsetof(PIN_VERIFY_STRUCTURE, abData));
+
+ /* Create T=1 block */
+ (void)t1_build(&((get_ccid_slot(reader_index))->t1),
+ sdata, 0, T1_I_BLOCK, &sbuf, NULL);
+
+ /* Increment the sequence numbers */
+ get_ccid_slot(reader_index)->t1.ns ^= 1;
+ get_ccid_slot(reader_index)->t1.nr ^= 1;
+
+ /* Copy the generated T=1 block prologue into the teoprologue
+ * of the CCID command */
+ memcpy(TxBuffer + offsetof(PIN_VERIFY_STRUCTURE, bTeoPrologue),
+ sdata, 3);
+ }
+
+ /* Build a CCID block from a PC/SC V2.02.05 Part 10 block */
+ for (a = 11, b = 0; b < TxLength; b++)
+ {
+ if (1 == b) /* bTimeOut2 field */
+ /* Ignore the second timeout as there's nothing we can do with
+ * it currently */
+ continue;
+
+ if ((b >= 15) && (b <= 18)) /* ulDataLength field (4 bytes) */
+ /* the ulDataLength field is not present in the CCID frame
+ * so do not copy */
+ continue;
+
+ /* copy the CCID block 'verbatim' */
+ cmd[a] = TxBuffer[b];
+ a++;
+ }
+
+ /* SPR532 and Case 1 APDU */
+ if ((SPR532 == ccid_descriptor->readerID)
+ /* bmPINBlockString = 0 => PIN length not inserted in APDU */
+ && (0 == TxBuffer[3])
+ /* case 1 APDU */
+ && (4 == TxBuffer[15]))
+ {
+ RESPONSECODE return_value;
+ unsigned char cmd_tmp[] = { 0x80, 0x02, 0x00 };
+ unsigned char res_tmp[1];
+ unsigned int res_length = sizeof(res_tmp);
+
+ /* the SPR532 will append the PIN code without any padding */
+ return_value = CmdEscape(reader_index, cmd_tmp, sizeof(cmd_tmp),
+ res_tmp, &res_length, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* we need to set bSeq again to avoid a "Duplicate frame detected"
+ * error since the bSeq of CmdEscape is now greater than bSeq set at
+ * the beginning of this function */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ }
+
+ i2dw(a - 10, cmd + 1); /* CCID message length */
+
+ old_read_timeout = ccid_descriptor -> readTimeout;
+ ccid_descriptor -> readTimeout = max(90, TxBuffer[0]+10)*1000; /* at least 90 seconds */
+
+ res = WritePort(reader_index, a, cmd);
+ if (STATUS_SUCCESS != res)
+ {
+ if (STATUS_NO_SUCH_DEVICE == res)
+ ret = IFD_NO_SUCH_DEVICE;
+ else
+ ret = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ ret = CCID_Receive(reader_index, RxLength, RxBuffer, NULL);
+
+ /* T=1 Protocol Management for a TPDU reader */
+ if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
+ && (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
+ {
+ /* timeout and cancel cases are faked by CCID_Receive() */
+ if ((2 == *RxLength)
+ /* the CCID command is rejected or failed */
+ || (IFD_SUCCESS != ret))
+ {
+ /* Decrement the sequence numbers since no TPDU was sent */
+ get_ccid_slot(reader_index)->t1.ns ^= 1;
+ get_ccid_slot(reader_index)->t1.nr ^= 1;
+ }
+ else
+ {
+ /* FIXME: manage T=1 error blocks */
+
+ /* defines from openct/proto-t1.c */
+ #define PCB 1
+ #define DATA 3
+ #define T1_S_BLOCK 0xC0
+ #define T1_S_RESPONSE 0x20
+ #define T1_S_TYPE(pcb) ((pcb) & 0x0F)
+ #define T1_S_WTX 0x03
+
+ /* WTX S-block */
+ if ((T1_S_BLOCK | T1_S_WTX) == RxBuffer[PCB])
+ {
+/*
+ * The Swiss health care card sends a WTX request before returning the
+ * SW code. If the reader is in TPDU the driver must manage the request
+ * itself.
+ *
+ * received: 00 C3 01 09 CB
+ * openct/proto-t1.c:432:t1_transceive() S-Block request received
+ * openct/proto-t1.c:489:t1_transceive() CT sent S-block with wtx=9
+ * sending: 00 E3 01 09 EB
+ * openct/proto-t1.c:667:t1_xcv() New timeout at WTX request: 23643 sec
+ * received: 00 40 02 90 00 D2
+*/
+ ct_buf_t tbuf;
+ unsigned char sblk[1]; /* we only need 1 byte of data */
+ t1_state_t *t1 = &get_ccid_slot(reader_index)->t1;
+ unsigned int slen;
+ int oldReadTimeout;
+
+ DEBUG_COMM2("CT sent S-block with wtx=%u", RxBuffer[DATA]);
+ t1->wtx = RxBuffer[DATA];
+
+ oldReadTimeout = ccid_descriptor->readTimeout;
+ if (t1->wtx > 1)
+ {
+ /* set the new temporary timeout at WTX card request */
+ ccid_descriptor->readTimeout *= t1->wtx;
+ DEBUG_INFO2("New timeout at WTX request: %d sec",
+ ccid_descriptor->readTimeout);
+ }
+
+ ct_buf_init(&tbuf, sblk, sizeof(sblk));
+ t1->wtx = RxBuffer[DATA];
+ ct_buf_putc(&tbuf, RxBuffer[DATA]);
+
+ slen = t1_build(t1, RxBuffer, 0,
+ T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(RxBuffer[PCB]),
+ &tbuf, NULL);
+
+ ret = CCID_Transmit(t1 -> lun, slen, RxBuffer, 0, t1->wtx);
+ if (ret != IFD_SUCCESS)
+ return ret;
+
+ /* I guess we have at least 6 bytes in RxBuffer */
+ *RxLength = 6;
+ ret = CCID_Receive(reader_index, RxLength, RxBuffer, NULL);
+ if (ret != IFD_SUCCESS)
+ return ret;
+
+ /* Restore initial timeout */
+ ccid_descriptor->readTimeout = oldReadTimeout;
+ }
+
+ /* get only the T=1 data */
+ memmove(RxBuffer, RxBuffer+3, *RxLength -4);
+ *RxLength -= 4; /* remove NAD, PCB, LEN and CRC */
+ }
+ }
+
+end:
+ ccid_descriptor -> readTimeout = old_read_timeout;
+ return ret;
+} /* SecurePINVerify */
+
+
+#ifdef BOGUS_PINPAD_FIRMWARE
+/*****************************************************************************
+ *
+ * has_gemalto_modify_pin_bug
+ *
+ ****************************************************************************/
+static int has_gemalto_modify_pin_bug(_ccid_descriptor *ccid_descriptor)
+{
+ /* Bug not present by default */
+ int has_bug = 0;
+
+ /* Covadis Véga-Alpha reader */
+ if (VEGAALPHA == ccid_descriptor->readerID)
+ {
+ /* This reader has the bug (uses a Gemalto firmware) */
+ has_bug = 1;
+ }
+ else
+ {
+ /* Gemalto reader */
+ if ((GET_VENDOR(ccid_descriptor->readerID) == VENDOR_GEMALTO))
+ {
+ has_bug = 1; /* assume it has the bug */
+
+ if (ccid_descriptor->gemalto_firmware_features &&
+ ccid_descriptor->gemalto_firmware_features->bNumberMessageFix)
+ {
+ /* A Gemalto reader has the ModifyPIN structure bug */
+ /* unless it explicitly reports it has been fixed */
+ has_bug = 0;
+ }
+ }
+ }
+
+ return has_bug;
+} /* has_gemalto_modify_pin_bug */
+#endif
+
+/*****************************************************************************
+ *
+ * SecurePINModify
+ *
+ ****************************************************************************/
+RESPONSECODE SecurePINModify(unsigned int reader_index,
+ unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength)
+{
+ unsigned char cmd[11+19+TxLength];
+ unsigned int a, b;
+ PIN_MODIFY_STRUCTURE *pms;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ int old_read_timeout;
+ RESPONSECODE ret;
+ status_t res;
+#ifdef BOGUS_PINPAD_FIRMWARE
+ int bNumberMessage = 0; /* for GemPC Pinpad */
+ int gemalto_modify_pin_bug;
+#endif
+
+ pms = (PIN_MODIFY_STRUCTURE *)TxBuffer;
+ cmd[0] = 0x69; /* Secure */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = 0; /* bBWI */
+ cmd[8] = 0; /* wLevelParameter */
+ cmd[9] = 0;
+ cmd[10] = 1; /* bPINOperation: PIN Modification */
+
+ if (TxLength < 24+4 /* 4 = APDU size */) /* command too short? */
+ {
+ DEBUG_INFO3("Command too short: %d < %d", TxLength, 24+4);
+ return IFD_NOT_SUPPORTED;
+ }
+
+ /* On little endian machines we are all set. */
+ /* If on big endian machine and caller is using host byte order */
+ if ((pms->ulDataLength + 24 == TxLength) &&
+ (bei2i((unsigned char*)(&pms->ulDataLength)) == pms->ulDataLength))
+ {
+ DEBUG_INFO1("Reversing order from big to little endian");
+ /* If ulDataLength is big endian, assume others are too */
+ /* reverse the byte order for 3 fields */
+ pms->wPINMaxExtraDigit = BSWAP_16(pms->wPINMaxExtraDigit);
+ pms->wLangId = BSWAP_16(pms->wLangId);
+ pms->ulDataLength = BSWAP_32(pms->ulDataLength);
+ }
+ /* At this point we now have the above 3 variables in little endian */
+
+
+ if (dw2i(TxBuffer, 20) + 24 != TxLength) /* ulDataLength field coherency */
+ {
+ DEBUG_INFO3("Wrong lengths: %d %d", dw2i(TxBuffer, 20) + 24, TxLength);
+ return IFD_NOT_SUPPORTED;
+ }
+
+ /* Make sure in the beginning if bNumberMessage is valid or not.
+ * 0xFF is the default value. */
+ if ((TxBuffer[11] > 3) && (TxBuffer[11] != 0xFF))
+ {
+ DEBUG_INFO2("Wrong bNumberMessage: %d", TxBuffer[11]);
+ return IFD_NOT_SUPPORTED;
+ }
+
+ /* Make sure bEntryValidationCondition is valid
+ * The Cherry XX44 reader crashes with a wrong value */
+ if ((0x00 == TxBuffer[10]) || (TxBuffer[10] > 0x07))
+ {
+ DEBUG_INFO2("Correct bEntryValidationCondition (was 0x%02X)",
+ TxBuffer[10]);
+ TxBuffer[10] = 0x02;
+ }
+
+#ifdef BOGUS_PINPAD_FIRMWARE
+ /* some firmwares are buggy so we try to "correct" the frame */
+ /*
+ * SPR 532 and Cherry ST 2000C has no display but requires _all_
+ * bMsgIndex fields with bNumberMessage set to 0.
+ */
+ if ((SPR532 == ccid_descriptor->readerID)
+ || (CHERRYST2000 == ccid_descriptor->readerID))
+ {
+ TxBuffer[11] = 0x03; /* set bNumberMessage to 3 so that
+ all bMsgIndex123 are filled */
+ TxBuffer[14] = TxBuffer[15] = TxBuffer[16] = 0; /* bMsgIndex123 */
+ }
+
+ /* the bug is a bit different than for the Cherry ST 2000C
+ * with bNumberMessage < 3 the command seems to be accepted
+ * and the card sends 6B 80 */
+ if (CHERRYXX44 == ccid_descriptor->readerID)
+ {
+ TxBuffer[11] = 0x03; /* set bNumberMessage to 3 so that
+ all bMsgIndex123 are filled */
+ }
+
+ /* bug circumvention for the GemPC Pinpad */
+ if ((GEMPCPINPAD == ccid_descriptor->readerID)
+ || (VEGAALPHA == ccid_descriptor->readerID))
+ {
+ /* The reader does not support, and actively reject, "max size reached"
+ * and "timeout occured" validation conditions */
+ if (0x02 != TxBuffer[10])
+ {
+ DEBUG_INFO2("Correct bEntryValidationCondition for GemPC Pinpad (was %d)",
+ TxBuffer[10]);
+ TxBuffer[10] = 0x02; /* validation key pressed */
+ }
+ }
+
+ gemalto_modify_pin_bug = has_gemalto_modify_pin_bug(ccid_descriptor);
+ if (gemalto_modify_pin_bug)
+ {
+ DEBUG_INFO1("Gemalto CCID Modify Pin Bug");
+
+ /* The reader requests a value for bMsgIndex2 and bMsgIndex3
+ * even if they should not be present. So we fake
+ * bNumberMessage=3. The real number of messages will be
+ * corrected later in the code */
+ bNumberMessage = TxBuffer[11];
+ if (0x03 != TxBuffer[11])
+ {
+ DEBUG_INFO2("Correct bNumberMessage for GemPC Pinpad (was %d)",
+ TxBuffer[11]);
+ TxBuffer[11] = 0x03; /* 3 messages */
+ }
+ }
+#endif
+
+ /* T=1 Protocol Management for a TPDU reader */
+ if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
+ && (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
+ {
+ ct_buf_t sbuf;
+ unsigned char sdata[T1_BUFFER_SIZE];
+
+ /* Initialize send buffer with the APDU */
+ ct_buf_set(&sbuf,
+ (void *)(TxBuffer + offsetof(PIN_MODIFY_STRUCTURE, abData)),
+ TxLength - offsetof(PIN_MODIFY_STRUCTURE, abData));
+
+ /* Create T=1 block */
+ (void)t1_build(&((get_ccid_slot(reader_index))->t1),
+ sdata, 0, T1_I_BLOCK, &sbuf, NULL);
+
+ /* Increment the sequence numbers */
+ get_ccid_slot(reader_index)->t1.ns ^= 1;
+ get_ccid_slot(reader_index)->t1.nr ^= 1;
+
+ /* Copy the generated T=1 block prologue into the teoprologue
+ * of the CCID command */
+ memcpy(TxBuffer + offsetof(PIN_MODIFY_STRUCTURE, bTeoPrologue),
+ sdata, 3);
+ }
+
+ /* Build a CCID block from a PC/SC V2.02.05 Part 10 block */
+
+ /* Do adjustments as needed - CCID spec is not exact with some
+ * details in the format of the structure, per-reader adaptions
+ * might be needed.
+ */
+ for (a = 11, b = 0; b < TxLength; b++)
+ {
+ if (1 == b) /* bTimeOut2 */
+ /* Ignore the second timeout as there's nothing we can do with it
+ * currently */
+ continue;
+
+ if (15 == b) /* bMsgIndex2 */
+ {
+ /* in CCID the bMsgIndex2 is present only if bNumberMessage != 0 */
+ if (0 == TxBuffer[11])
+ continue;
+ }
+
+ if (16 == b) /* bMsgIndex3 */
+ {
+ /* in CCID the bMsgIndex3 is present only if bNumberMessage == 3 */
+ if (TxBuffer[11] < 3)
+ continue;
+ }
+
+ if ((b >= 20) && (b <= 23)) /* ulDataLength field (4 bytes) */
+ /* the ulDataLength field is not present in the CCID frame
+ * so do not copy */
+ continue;
+
+ /* copy to the CCID block 'verbatim' */
+ cmd[a] = TxBuffer[b];
+ a++;
+ }
+
+#ifdef BOGUS_PINPAD_FIRMWARE
+ if ((SPR532 == ccid_descriptor->readerID)
+ || (CHERRYST2000 == ccid_descriptor->readerID))
+ {
+ cmd[21] = 0x00; /* set bNumberMessage to 0 */
+ }
+
+ if (gemalto_modify_pin_bug)
+ cmd[21] = bNumberMessage; /* restore the real value */
+#endif
+
+ /* We know the size of the CCID message now */
+ i2dw(a - 10, cmd + 1); /* command length (includes bPINOperation) */
+
+ old_read_timeout = ccid_descriptor -> readTimeout;
+ ccid_descriptor -> readTimeout = max(90, TxBuffer[0]+10)*1000; /* at least 90 seconds */
+
+ res = WritePort(reader_index, a, cmd);
+ if (STATUS_SUCCESS != res)
+ {
+ if (STATUS_NO_SUCH_DEVICE == res)
+ ret = IFD_NO_SUCH_DEVICE;
+ else
+ ret = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ ret = CCID_Receive(reader_index, RxLength, RxBuffer, NULL);
+
+ /* T=1 Protocol Management for a TPDU reader */
+ if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
+ && (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
+ {
+ /* timeout and cancel cases are faked by CCID_Receive() */
+ if ((2 == *RxLength)
+ /* the CCID command is rejected or failed */
+ || (IFD_SUCCESS != ret))
+ {
+ /* Decrement the sequence numbers since no TPDU was sent */
+ get_ccid_slot(reader_index)->t1.ns ^= 1;
+ get_ccid_slot(reader_index)->t1.nr ^= 1;
+ }
+ else
+ {
+ /* get only the T=1 data */
+ /* FIXME: manage T=1 error blocks */
+ memmove(RxBuffer, RxBuffer+3, *RxLength -4);
+ *RxLength -= 4; /* remove NAD, PCB, LEN and CRC */
+ }
+ }
+
+end:
+ ccid_descriptor -> readTimeout = old_read_timeout;
+ return ret;
+} /* SecurePINModify */
+
+
+/*****************************************************************************
+ *
+ * Escape
+ *
+ ****************************************************************************/
+RESPONSECODE CmdEscape(unsigned int reader_index,
+ const unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength, unsigned int timeout)
+{
+ unsigned char *cmd_in, *cmd_out;
+ status_t res;
+ unsigned int length_in, length_out;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ int old_read_timeout;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ /* a value of 0 do not change the default read timeout */
+ if (timeout > 0)
+ {
+ old_read_timeout = ccid_descriptor -> readTimeout;
+ ccid_descriptor -> readTimeout = timeout;
+ }
+
+again:
+ /* allocate buffers */
+ length_in = 10 + TxLength;
+ if (NULL == (cmd_in = malloc(length_in)))
+ {
+ return_value = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ length_out = 10 + *RxLength;
+ if (NULL == (cmd_out = malloc(length_out)))
+ {
+ free(cmd_in);
+ return_value = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ cmd_in[0] = 0x6B; /* PC_to_RDR_Escape */
+ i2dw(length_in - 10, cmd_in+1); /* dwLength */
+ cmd_in[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd_in[6] = (*ccid_descriptor->pbSeq)++;
+ cmd_in[7] = cmd_in[8] = cmd_in[9] = 0; /* RFU */
+
+ /* copy the command */
+ memcpy(&cmd_in[10], TxBuffer, TxLength);
+
+ res = WritePort(reader_index, length_in, cmd_in);
+ free(cmd_in);
+ if (res != STATUS_SUCCESS)
+ {
+ free(cmd_out);
+ if (STATUS_NO_SUCH_DEVICE == res)
+ return_value = IFD_NO_SUCH_DEVICE;
+ else
+ return_value = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+time_request:
+ length_out = 10 + *RxLength;
+ res = ReadPort(reader_index, &length_out, cmd_out);
+
+ /* replay the command if NAK
+ * This (generally) happens only for the first command sent to the reader
+ * with the serial protocol so it is not really needed for all the other
+ * ReadPort() calls */
+ if (STATUS_COMM_NAK == res)
+ {
+ free(cmd_out);
+ goto again;
+ }
+
+ if (res != STATUS_SUCCESS)
+ {
+ free(cmd_out);
+ if (STATUS_NO_SUCH_DEVICE == res)
+ return_value = IFD_NO_SUCH_DEVICE;
+ else
+ return_value = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ if (length_out < STATUS_OFFSET+1)
+ {
+ free(cmd_out);
+ DEBUG_CRITICAL2("Not enough data received: %d bytes", length_out);
+ return_value = IFD_COMMUNICATION_ERROR;
+ goto end;
+ }
+
+ if (cmd_out[STATUS_OFFSET] & CCID_TIME_EXTENSION)
+ {
+ DEBUG_COMM2("Time extension requested: 0x%02X", cmd_out[ERROR_OFFSET]);
+ goto time_request;
+ }
+
+ if (cmd_out[STATUS_OFFSET] & CCID_COMMAND_FAILED)
+ {
+ ccid_error(cmd_out[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+
+ /* copy the response */
+ length_out = dw2i(cmd_out, 1);
+ if (length_out > *RxLength)
+ length_out = *RxLength;
+ *RxLength = length_out;
+ memcpy(RxBuffer, &cmd_out[10], length_out);
+
+ free(cmd_out);
+
+end:
+ if (timeout > 0)
+ ccid_descriptor -> readTimeout = old_read_timeout;
+
+ return return_value;
+} /* Escape */
+
+
+/*****************************************************************************
+ *
+ * CmdPowerOff
+ *
+ ****************************************************************************/
+RESPONSECODE CmdPowerOff(unsigned int reader_index)
+{
+ unsigned char cmd[10];
+ status_t res;
+ unsigned int length;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+#ifndef TWIN_SERIAL
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+
+ /* PowerOff */
+ r = ControlUSB(reader_index, 0x21, 0x63, 0, NULL, 0);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power Off failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char buffer[3];
+
+ /* PowerOff */
+ r = ControlUSB(reader_index, 0x21, 0x63, 0, NULL, 0);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power Off failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* SlotStatus */
+ r = ControlUSB(reader_index, 0xA1, 0x81, 0, buffer, sizeof(buffer));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC SlotStatus failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+#endif
+
+ cmd[0] = 0x63; /* IccPowerOff */
+ cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
+
+ res = WritePort(reader_index, sizeof(cmd), cmd);
+ CHECK_STATUS(res)
+
+ length = sizeof(cmd);
+ res = ReadPort(reader_index, &length, cmd);
+ CHECK_STATUS(res)
+
+ if (length < STATUS_OFFSET+1)
+ {
+ DEBUG_CRITICAL2("Not enough data received: %d bytes", length);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
+ {
+ ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+
+ return return_value;
+} /* CmdPowerOff */
+
+
+/*****************************************************************************
+ *
+ * CmdGetSlotStatus
+ *
+ ****************************************************************************/
+RESPONSECODE CmdGetSlotStatus(unsigned int reader_index, unsigned char buffer[])
+{
+ unsigned char cmd[10];
+ status_t res;
+ unsigned int length;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+#ifndef TWIN_SERIAL
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char status[1];
+
+again_status:
+ /* SlotStatus */
+ r = ControlUSB(reader_index, 0xA1, 0xA0, 0, status, sizeof(status));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Slot Status failed: %s", strerror(errno));
+ if (ENODEV == errno)
+ return IFD_NO_SUCH_DEVICE;
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* busy */
+ if (status[0] & 0x40)
+ {
+ DEBUG_INFO2("Busy: 0x%02X", status[0]);
+ (void)usleep(1000 * 10);
+ goto again_status;
+ }
+
+ /* simulate a CCID bStatus */
+ /* present and active by default */
+ buffer[7] = CCID_ICC_PRESENT_ACTIVE;
+
+ /* mute */
+ if (0x80 == status[0])
+ buffer[7] = CCID_ICC_ABSENT;
+
+ /* store the status for CmdXfrBlockCHAR_T0() */
+ buffer[0] = status[0];
+
+ return IFD_SUCCESS;
+ }
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char buffer_tmp[3];
+
+ /* SlotStatus */
+ r = ControlUSB(reader_index, 0xA1, 0x81, 0, buffer_tmp,
+ sizeof(buffer_tmp));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Slot Status failed: %s", strerror(errno));
+ if (ENODEV == errno)
+ return IFD_NO_SUCH_DEVICE;
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* simulate a CCID bStatus */
+ switch (buffer_tmp[1] & 0x03)
+ {
+ case 0:
+ buffer[7] = CCID_ICC_PRESENT_ACTIVE;
+ break;
+ case 1:
+ buffer[7] = CCID_ICC_PRESENT_INACTIVE;
+ break;
+ case 2:
+ case 3:
+ buffer[7] = CCID_ICC_ABSENT;
+ }
+ return IFD_SUCCESS;
+ }
+#endif
+
+ cmd[0] = 0x65; /* GetSlotStatus */
+ cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
+
+ res = WritePort(reader_index, sizeof(cmd), cmd);
+ CHECK_STATUS(res)
+
+ length = SIZE_GET_SLOT_STATUS;
+ res = ReadPort(reader_index, &length, buffer);
+ CHECK_STATUS(res)
+
+ if (length < STATUS_OFFSET+1)
+ {
+ DEBUG_CRITICAL2("Not enough data received: %d bytes", length);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if ((buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
+ /* card absent or mute is not an communication error */
+ && (buffer[ERROR_OFFSET] != 0xFE))
+ {
+ return_value = IFD_COMMUNICATION_ERROR;
+ ccid_error(buffer[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
+ }
+
+ return return_value;
+} /* CmdGetSlotStatus */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlock
+ *
+ ****************************************************************************/
+RESPONSECODE CmdXfrBlock(unsigned int reader_index, unsigned int tx_length,
+ unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[], int protocol)
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ /* APDU or TPDU? */
+ switch (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)
+ {
+ case CCID_CLASS_TPDU:
+ if (protocol == T_0)
+ return_value = CmdXfrBlockTPDU_T0(reader_index,
+ tx_length, tx_buffer, rx_length, rx_buffer);
+ else
+ if (protocol == T_1)
+ return_value = CmdXfrBlockTPDU_T1(reader_index, tx_length,
+ tx_buffer, rx_length, rx_buffer);
+ else
+ return_value = IFD_PROTOCOL_NOT_SUPPORTED;
+ break;
+
+ case CCID_CLASS_SHORT_APDU:
+ return_value = CmdXfrBlockTPDU_T0(reader_index,
+ tx_length, tx_buffer, rx_length, rx_buffer);
+ break;
+
+ case CCID_CLASS_EXTENDED_APDU:
+ return_value = CmdXfrBlockAPDU_extended(reader_index,
+ tx_length, tx_buffer, rx_length, rx_buffer);
+ break;
+
+ case CCID_CLASS_CHARACTER:
+ if (protocol == T_0)
+ return_value = CmdXfrBlockCHAR_T0(reader_index, tx_length,
+ tx_buffer, rx_length, rx_buffer);
+ else
+ if (protocol == T_1)
+ return_value = CmdXfrBlockTPDU_T1(reader_index, tx_length,
+ tx_buffer, rx_length, rx_buffer);
+ else
+ return_value = IFD_PROTOCOL_NOT_SUPPORTED;
+ break;
+
+ default:
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+
+ return return_value;
+} /* CmdXfrBlock */
+
+
+/*****************************************************************************
+ *
+ * CCID_Transmit
+ *
+ ****************************************************************************/
+RESPONSECODE CCID_Transmit(unsigned int reader_index, unsigned int tx_length,
+ const unsigned char tx_buffer[], unsigned short rx_length, unsigned char bBWI)
+{
+ unsigned char cmd[10+tx_length]; /* CCID + APDU buffer */
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ status_t ret;
+
+#ifndef TWIN_SERIAL
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+
+ /* Xfr Block */
+ r = ControlUSB(reader_index, 0x21, 0x65, 0,
+ (unsigned char *)tx_buffer, tx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Xfr Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+
+ /* nul block so we are chaining */
+ if (NULL == tx_buffer)
+ rx_length = 0x10; /* bLevelParameter */
+
+ /* Xfr Block */
+ DEBUG_COMM2("chain parameter: %d", rx_length);
+ r = ControlUSB(reader_index, 0x21, 0x65, rx_length << 8,
+ (unsigned char *)tx_buffer, tx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Xfr Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+#endif
+
+ cmd[0] = 0x6F; /* XfrBlock */
+ i2dw(tx_length, cmd+1); /* APDU length */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = bBWI; /* extend block waiting timeout */
+ cmd[8] = rx_length & 0xFF; /* Expected length, in character mode only */
+ cmd[9] = (rx_length >> 8) & 0xFF;
+
+ memcpy(cmd+10, tx_buffer, tx_length);
+
+ ret = WritePort(reader_index, 10+tx_length, cmd);
+ CHECK_STATUS(ret)
+
+ return IFD_SUCCESS;
+} /* CCID_Transmit */
+
+
+/*****************************************************************************
+ *
+ * CCID_Receive
+ *
+ ****************************************************************************/
+RESPONSECODE CCID_Receive(unsigned int reader_index, unsigned int *rx_length,
+ unsigned char rx_buffer[], unsigned char *chain_parameter)
+{
+ unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
+ unsigned int length;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ status_t ret;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ unsigned int old_timeout;
+
+#ifndef TWIN_SERIAL
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+ int r;
+
+ /* wait for ready */
+ r = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* Data Block */
+ r = ControlUSB(reader_index, 0xA1, 0x6F, 0, rx_buffer, *rx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* we need to store returned value */
+ *rx_length = r;
+
+ return IFD_SUCCESS;
+ }
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char rx_tmp[4];
+ unsigned char *old_rx_buffer = NULL;
+ int old_rx_length = 0;
+
+ /* read a nul block. buffer need to be at least 4-bytes */
+ if (NULL == rx_buffer)
+ {
+ rx_buffer = rx_tmp;
+ *rx_length = sizeof(rx_tmp);
+ }
+
+ /* the buffer must be 4 bytes minimum for ICCD-B */
+ if (*rx_length < 4)
+ {
+ old_rx_buffer = rx_buffer;
+ old_rx_length = *rx_length;
+ rx_buffer = rx_tmp;
+ *rx_length = sizeof(rx_tmp);
+ }
+
+time_request_ICCD_B:
+ /* Data Block */
+ r = ControlUSB(reader_index, 0xA1, 0x6F, 0, rx_buffer, *rx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* copy from the 4 bytes buffer if used */
+ if (old_rx_buffer)
+ {
+ memcpy(old_rx_buffer, rx_buffer, min(r, old_rx_length));
+ rx_buffer = old_rx_buffer;
+ }
+
+ /* bResponseType */
+ switch (rx_buffer[0])
+ {
+ case 0x00:
+ /* the abData field contains the information created by the
+ * preceding request */
+ break;
+
+ case 0x40:
+ /* Status Information */
+ ccid_error(rx_buffer[2], __FILE__, __LINE__, __FUNCTION__);
+ return IFD_COMMUNICATION_ERROR;
+
+ case 0x80:
+ /* Polling */
+ {
+ int delay;
+
+ delay = (rx_buffer[2] << 8) + rx_buffer[1];
+ DEBUG_COMM2("Pooling delay: %d", delay);
+
+ if (0 == delay)
+ /* host select the delay */
+ delay = 1;
+ (void)usleep(delay * 1000 * 10);
+ goto time_request_ICCD_B;
+ }
+
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x10:
+ /* Extended case
+ * Only valid for Data Block frames */
+ if (chain_parameter)
+ *chain_parameter = rx_buffer[0];
+ break;
+
+ default:
+ DEBUG_CRITICAL2("Unknown bResponseType: 0x%02X", rx_buffer[0]);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ memmove(rx_buffer, rx_buffer+1, r-1);
+ *rx_length = r-1;
+
+ return IFD_SUCCESS;
+ }
+#endif
+
+ /* store the original value of read timeout*/
+ old_timeout = ccid_descriptor -> readTimeout;
+
+time_request:
+ length = sizeof(cmd);
+ ret = ReadPort(reader_index, &length, cmd);
+
+ /* restore the original value of read timeout */
+ ccid_descriptor -> readTimeout = old_timeout;
+ CHECK_STATUS(ret)
+
+ if (length < STATUS_OFFSET+1)
+ {
+ DEBUG_CRITICAL2("Not enough data received: %d bytes", length);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
+ {
+ ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
+ switch (cmd[ERROR_OFFSET])
+ {
+ case 0xEF: /* cancel */
+ if (*rx_length < 2)
+ return IFD_COMMUNICATION_ERROR;
+ rx_buffer[0]= 0x64;
+ rx_buffer[1]= 0x01;
+ *rx_length = 2;
+ return IFD_SUCCESS;
+
+ case 0xF0: /* timeout */
+ if (*rx_length < 2)
+ return IFD_COMMUNICATION_ERROR;
+ rx_buffer[0]= 0x64;
+ rx_buffer[1]= 0x00;
+ *rx_length = 2;
+ return IFD_SUCCESS;
+
+ case 0xFD: /* Parity error during exchange */
+ return IFD_PARITY_ERROR;
+
+ default:
+ return IFD_COMMUNICATION_ERROR;
+ }
+ }
+
+ if (cmd[STATUS_OFFSET] & CCID_TIME_EXTENSION)
+ {
+ DEBUG_COMM2("Time extension requested: 0x%02X", cmd[ERROR_OFFSET]);
+
+ /* compute the new value of read timeout */
+ if (cmd[ERROR_OFFSET] > 0)
+ ccid_descriptor -> readTimeout *= cmd[ERROR_OFFSET];
+
+ DEBUG_COMM2("New timeout: %d ms", ccid_descriptor -> readTimeout);
+ goto time_request;
+ }
+
+ /* we have read less (or more) data than the CCID frame says to contain */
+ if (length-10 != dw2i(cmd, 1))
+ {
+ DEBUG_CRITICAL3("Can't read all data (%d out of %d expected)",
+ length-10, dw2i(cmd, 1));
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+
+ length = dw2i(cmd, 1);
+ if (length <= *rx_length)
+ *rx_length = length;
+ else
+ {
+ DEBUG_CRITICAL2("overrun by %d bytes", length - *rx_length);
+ length = *rx_length;
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ /* Kobil firmware bug. No support for chaining */
+ if (length && (NULL == rx_buffer))
+ {
+ DEBUG_CRITICAL2("Nul block expected but got %d bytes", length);
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+ else
+ memcpy(rx_buffer, cmd+10, length);
+
+ /* Extended case?
+ * Only valid for RDR_to_PC_DataBlock frames */
+ if (chain_parameter)
+ *chain_parameter = cmd[CHAIN_PARAMETER_OFFSET];
+
+ return return_value;
+} /* CCID_Receive */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlockAPDU_extended
+ *
+ ****************************************************************************/
+static RESPONSECODE CmdXfrBlockAPDU_extended(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[])
+{
+ RESPONSECODE return_value;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ unsigned char chain_parameter;
+ unsigned int local_tx_length, sent_length;
+ unsigned int local_rx_length = 0, received_length;
+ int buffer_overflow = 0;
+
+ if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ /* length is on 16-bits only
+ * if a size > 0x1000 is used then usb_control_msg() fails with
+ * "Invalid argument" */
+ if (*rx_length > 0x1000)
+ *rx_length = 0x1000;
+ }
+
+ DEBUG_COMM2("T=0 (extended): %d bytes", tx_length);
+
+ /* send the APDU */
+ sent_length = 0;
+
+ /* we suppose one command is enough */
+ chain_parameter = 0x00;
+
+ local_tx_length = tx_length - sent_length;
+ if (local_tx_length > CMD_BUF_SIZE)
+ {
+ local_tx_length = CMD_BUF_SIZE;
+ /* the command APDU begins with this command, and continue in the next
+ * PC_to_RDR_XfrBlock */
+ chain_parameter = 0x01;
+ }
+ if (local_tx_length > ccid_descriptor->dwMaxCCIDMessageLength-10)
+ {
+ local_tx_length = ccid_descriptor->dwMaxCCIDMessageLength-10;
+ chain_parameter = 0x01;
+ }
+
+send_next_block:
+ return_value = CCID_Transmit(reader_index, local_tx_length, tx_buffer,
+ chain_parameter, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ sent_length += local_tx_length;
+ tx_buffer += local_tx_length;
+
+ /* we just sent the last block (0x02) or only one block was needded (0x00) */
+ if ((0x02 == chain_parameter) || (0x00 == chain_parameter))
+ goto receive_block;
+
+ /* read a nul block */
+ return_value = CCID_Receive(reader_index, &local_rx_length, NULL, NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* size of the next block */
+ if (tx_length - sent_length > local_tx_length)
+ {
+ /* the abData field continues a command APDU and
+ * another block is to follow */
+ chain_parameter = 0x03;
+ }
+ else
+ {
+ /* this abData field continues a command APDU and ends
+ * the APDU command */
+ chain_parameter = 0x02;
+
+ /* last (smaller) block */
+ local_tx_length = tx_length - sent_length;
+ }
+
+ goto send_next_block;
+
+receive_block:
+ /* receive the APDU */
+ received_length = 0;
+
+receive_next_block:
+ local_rx_length = *rx_length - received_length;
+ return_value = CCID_Receive(reader_index, &local_rx_length, rx_buffer,
+ &chain_parameter);
+ if (IFD_ERROR_INSUFFICIENT_BUFFER == return_value)
+ {
+ buffer_overflow = 1;
+
+ /* we continue to read all the response APDU */
+ return_value = IFD_SUCCESS;
+ }
+
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* advance in the reiceiving buffer */
+ rx_buffer += local_rx_length;
+ received_length += local_rx_length;
+
+ switch (chain_parameter)
+ {
+ /* the response APDU begins and ends in this command */
+ case 0x00:
+ /* this abData field continues the response APDU and ends the response
+ * APDU */
+ case 0x02:
+ break;
+
+ /* the response APDU begins with this command and is to continue */
+ case 0x01:
+ /* this abData field continues the response APDU and another block is
+ * to follow */
+ case 0x03:
+ /* empty abData field, continuation of the command APDU is expected in
+ * next PC_to_RDR_XfrBlock command */
+ case 0x10:
+ /* send a nul block */
+ /* set wLevelParameter to 0010h: empty abData field,
+ * continuation of response APDU is
+ * expected in the next RDR_to_PC_DataBlock. */
+ return_value = CCID_Transmit(reader_index, 0, NULL, 0x10, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ goto receive_next_block;
+ }
+
+ *rx_length = received_length;
+
+ /* generate an overflow detected by pcscd */
+ if (buffer_overflow)
+ (*rx_length)++;
+
+ return IFD_SUCCESS;
+} /* CmdXfrBlockAPDU_extended */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlockTPDU_T0
+ *
+ ****************************************************************************/
+static RESPONSECODE CmdXfrBlockTPDU_T0(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[])
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ DEBUG_COMM2("T=0: %d bytes", tx_length);
+
+ /* command length too big for CCID reader? */
+ if (tx_length > ccid_descriptor->dwMaxCCIDMessageLength-10)
+ {
+#ifdef BOGUS_SCM_FIRMWARE_FOR_dwMaxCCIDMessageLength
+ if (263 == ccid_descriptor->dwMaxCCIDMessageLength)
+ {
+ DEBUG_INFO3("Command too long (%d bytes) for max: %d bytes."
+ " SCM reader with bogus firmware?",
+ tx_length, ccid_descriptor->dwMaxCCIDMessageLength-10);
+ }
+ else
+#endif
+ {
+ DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
+ tx_length, ccid_descriptor->dwMaxCCIDMessageLength-10);
+ return IFD_COMMUNICATION_ERROR;
+ }
+ }
+
+ /* command length too big for CCID driver? */
+ if (tx_length > CMD_BUF_SIZE)
+ {
+ DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
+ tx_length, CMD_BUF_SIZE);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return_value = CCID_Transmit(reader_index, tx_length, tx_buffer, 0, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ return CCID_Receive(reader_index, rx_length, rx_buffer, NULL);
+} /* CmdXfrBlockTPDU_T0 */
+
+
+/*****************************************************************************
+ *
+ * T0CmdParsing
+ *
+ ****************************************************************************/
+static RESPONSECODE T0CmdParsing(unsigned char *cmd, unsigned int cmd_len,
+ /*@out@*/ unsigned int *exp_len)
+{
+ *exp_len = 0;
+
+ /* Ref: 7816-4 Annex A */
+ switch (cmd_len)
+ {
+ case 4: /* Case 1 */
+ *exp_len = 2; /* SW1 and SW2 only */
+ break;
+
+ case 5: /* Case 2 */
+ if (cmd[4] != 0)
+ *exp_len = cmd[4] + 2;
+ else
+ *exp_len = 256 + 2;
+ break;
+
+ default: /* Case 3 */
+ if (cmd_len > 5 && cmd_len == (unsigned int)(cmd[4] + 5))
+ *exp_len = 2; /* SW1 and SW2 only */
+ else
+ return IFD_COMMUNICATION_ERROR; /* situation not supported */
+ break;
+ }
+
+ return IFD_SUCCESS;
+} /* T0CmdParsing */
+
+
+/*****************************************************************************
+ *
+ * T0ProcACK
+ *
+ ****************************************************************************/
+static RESPONSECODE T0ProcACK(unsigned int reader_index,
+ unsigned char **snd_buf, unsigned int *snd_len,
+ unsigned char **rcv_buf, unsigned int *rcv_len,
+ unsigned char **in_buf, unsigned int *in_len,
+ unsigned int proc_len, int is_rcv)
+{
+ RESPONSECODE return_value;
+ unsigned int ret_len;
+
+ DEBUG_COMM2("Enter, is_rcv = %d", is_rcv);
+
+ if (is_rcv == 1)
+ { /* Receiving mode */
+ unsigned int remain_len;
+ unsigned char tmp_buf[512];
+
+ if (*in_len > 0)
+ { /* There are still available data in our buffer */
+ if (*in_len >= proc_len)
+ {
+ /* We only need to get the data from our buffer */
+ memcpy(*rcv_buf, *in_buf, proc_len);
+ *rcv_buf += proc_len;
+ *in_buf += proc_len;
+ *rcv_len += proc_len;
+ *in_len -= proc_len;
+
+ return IFD_SUCCESS;
+ }
+ else
+ {
+ /* Move all data in the input buffer to the reply buffer */
+ remain_len = proc_len - *in_len;
+ memcpy(*rcv_buf, *in_buf, *in_len);
+ *rcv_buf += *in_len;
+ *in_buf += *in_len;
+ *rcv_len += *in_len;
+ *in_len = 0;
+ }
+ }
+ else
+ /* There is no data in our tmp_buf,
+ * we have to read all data we needed */
+ remain_len = proc_len;
+
+ /* Read the expected data from the smartcard */
+ if (*in_len != 0)
+ {
+ DEBUG_CRITICAL("*in_len != 0");
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ memset(tmp_buf, 0, sizeof(tmp_buf));
+
+#ifdef O2MICRO_OZ776_PATCH
+ if((0 != remain_len) && (0 == (remain_len + 10) % 64))
+ {
+ /* special hack to avoid a command of size modulo 64
+ * we send two commands instead */
+ ret_len = 1;
+ return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ return_value = CCID_Receive(reader_index, &ret_len, tmp_buf, NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ ret_len = remain_len - 1;
+ return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ return_value = CCID_Receive(reader_index, &ret_len, &tmp_buf[1],
+ NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ ret_len += 1;
+ }
+ else
+#endif
+ {
+ ret_len = remain_len;
+ return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ return_value = CCID_Receive(reader_index, &ret_len, tmp_buf, NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ }
+ memcpy(*rcv_buf, tmp_buf, remain_len);
+ *rcv_buf += remain_len, *rcv_len += remain_len;
+
+ /* If ret_len != remain_len, our logic is erroneous */
+ if (ret_len != remain_len)
+ {
+ DEBUG_CRITICAL("ret_len != remain_len");
+ return IFD_COMMUNICATION_ERROR;
+ }
+ }
+ else
+ { /* Sending mode */
+
+ return_value = CCID_Transmit(reader_index, proc_len, *snd_buf, 1, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ *snd_len -= proc_len;
+ *snd_buf += proc_len;
+ }
+
+ DEBUG_COMM("Exit");
+
+ return IFD_SUCCESS;
+} /* T0ProcACK */
+
+
+/*****************************************************************************
+ *
+ * T0ProcSW1
+ *
+ ****************************************************************************/
+static RESPONSECODE T0ProcSW1(unsigned int reader_index,
+ unsigned char *rcv_buf, unsigned int *rcv_len,
+ unsigned char *in_buf, unsigned int in_len)
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ UCHAR tmp_buf[512];
+ unsigned char sw1, sw2;
+
+ /* store the SW1 */
+ sw1 = *rcv_buf = *in_buf;
+ rcv_buf++;
+ in_buf++;
+ in_len--;
+ (*rcv_len)++;
+
+ /* store the SW2 */
+ if (0 == in_len)
+ {
+ return_value = CCID_Transmit(reader_index, 0, rcv_buf, 1, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ in_len = 1;
+
+ return_value = CCID_Receive(reader_index, &in_len, tmp_buf, NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ in_buf = tmp_buf;
+ }
+ sw2 = *rcv_buf = *in_buf;
+ in_len--;
+ (*rcv_len)++;
+
+ DEBUG_COMM3("Exit: SW=%02X %02X", sw1, sw2);
+
+ return return_value;
+} /* T0ProcSW1 */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlockCHAR_T0
+ *
+ ****************************************************************************/
+static RESPONSECODE CmdXfrBlockCHAR_T0(unsigned int reader_index,
+ unsigned int snd_len, unsigned char snd_buf[], unsigned int *rcv_len,
+ unsigned char rcv_buf[])
+{
+ int is_rcv;
+ unsigned char cmd[5];
+ unsigned char tmp_buf[512];
+ unsigned int exp_len, in_len;
+ unsigned char ins, *in_buf;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ DEBUG_COMM2("T=0: %d bytes", snd_len);
+
+ if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+ unsigned int backup_len;
+
+ /* length is on 16-bits only
+ * if a size > 0x1000 is used then usb_control_msg() fails with
+ * "Invalid argument" */
+ if (*rcv_len > 0x1000)
+ *rcv_len = 0x1000;
+
+ backup_len = *rcv_len;
+
+ /* Command to send to the smart card (must be 5 bytes) */
+ memset(cmd, 0, sizeof(cmd));
+ if (snd_len == 4)
+ {
+ memcpy(cmd, snd_buf, 4);
+ snd_buf += 4;
+ snd_len -= 4;
+ }
+ else
+ {
+ memcpy(cmd, snd_buf, 5);
+ snd_buf += 5;
+ snd_len -= 5;
+ }
+
+ /* at most 5 bytes */
+ return_value = CCID_Transmit(reader_index, 5, cmd, 0, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* wait for ready */
+ pcbuffer[0] = 0;
+ return_value = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ if (0x10 == pcbuffer[0])
+ {
+ if (snd_len > 0)
+ {
+ /* continue sending the APDU */
+ return_value = CCID_Transmit(reader_index, snd_len, snd_buf,
+ 0, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ }
+ else
+ {
+ /* read apdu data */
+ return_value = CCID_Receive(reader_index, rcv_len, rcv_buf,
+ NULL);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ }
+ }
+
+ return_value = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* SW1-SW2 available */
+ if (0x20 == pcbuffer[0])
+ {
+ /* backup apdu data length */
+ /* if no data recieved before - backup length must be zero */
+ backup_len = (backup_len == *rcv_len) ? 0 : *rcv_len;
+
+ /* wait for 2 bytes (SW1-SW2) */
+ *rcv_len = 2;
+
+ return_value = CCID_Receive(reader_index, rcv_len,
+ rcv_buf + backup_len, NULL);
+ if (return_value != IFD_SUCCESS)
+ DEBUG_CRITICAL("CCID_Receive failed");
+
+ /* restore recieved length */
+ *rcv_len += backup_len;
+ }
+ return return_value;
+ }
+
+ in_buf = tmp_buf;
+ in_len = 0;
+ *rcv_len = 0;
+
+ return_value = T0CmdParsing(snd_buf, snd_len, &exp_len);
+ if (return_value != IFD_SUCCESS)
+ {
+ DEBUG_CRITICAL("T0CmdParsing failed");
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (snd_len == 5 || snd_len == 4)
+ is_rcv = 1;
+ else
+ is_rcv = 0;
+
+ /* Command to send to the smart card (must be 5 bytes, from 7816 p.15) */
+ memset(cmd, 0, sizeof(cmd));
+ if (snd_len == 4)
+ {
+ memcpy(cmd, snd_buf, 4);
+ snd_buf += 4;
+ snd_len -= 4;
+ }
+ else
+ {
+ memcpy(cmd, snd_buf, 5);
+ snd_buf += 5;
+ snd_len -= 5;
+ }
+
+ /* Make sure this is a valid command by checking the INS field */
+ ins = cmd[1];
+ if ((ins & 0xF0) == 0x60 || /* 7816-3 8.3.2 */
+ (ins & 0xF0) == 0x90)
+ {
+ DEBUG_CRITICAL2("fatal: INS (0x%02X) = 0x6X or 0x9X", ins);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return_value = CCID_Transmit(reader_index, 5, cmd, 1, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ while (1)
+ {
+ if (in_len == 0)
+ {
+ in_len = 1;
+ return_value = CCID_Receive(reader_index, &in_len, tmp_buf, NULL);
+ if (return_value != IFD_SUCCESS)
+ {
+ DEBUG_CRITICAL("CCID_Receive failed");
+ return return_value;
+ }
+ in_buf = tmp_buf;
+ }
+ if (in_len == 0)
+ {
+ /* Suppose we should be able to get data.
+ * If not, error. Set the time-out error */
+ DEBUG_CRITICAL("error: in_len = 0");
+ return IFD_RESPONSE_TIMEOUT;
+ }
+
+ /* Start to process the procedure bytes */
+ if (*in_buf == 0x60)
+ {
+ in_len = 0;
+ return_value = CCID_Transmit(reader_index, 0, cmd, 1, 0);
+
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ continue;
+ }
+ else if (*in_buf == ins || *in_buf == (ins ^ 0x01))
+ {
+ /* ACK => To transfer all remaining data bytes */
+ in_buf++, in_len--;
+ if (is_rcv)
+ return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
+ &rcv_buf, rcv_len, &in_buf, &in_len, exp_len - *rcv_len, 1);
+ else
+ return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
+ &rcv_buf, rcv_len, &in_buf, &in_len, snd_len, 0);
+
+ if (*rcv_len == exp_len)
+ return return_value;
+
+ continue;
+ }
+ else if (*in_buf == (ins ^ 0xFF) || *in_buf == (ins ^ 0xFE))
+ {
+ /* ACK => To transfer 1 remaining bytes */
+ in_buf++, in_len--;
+ return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
+ &rcv_buf, rcv_len, &in_buf, &in_len, 1, is_rcv);
+
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ continue;
+ }
+ else if ((*in_buf & 0xF0) == 0x60 || (*in_buf & 0xF0) == 0x90)
+ /* SW1 */
+ return T0ProcSW1(reader_index, rcv_buf, rcv_len, in_buf, in_len);
+
+ /* Error, unrecognized situation found */
+ DEBUG_CRITICAL2("Unrecognized Procedure byte (0x%02X) found!", *in_buf);
+ return return_value;
+ }
+
+ return return_value;
+} /* CmdXfrBlockCHAR_T0 */
+
+
+/*****************************************************************************
+ *
+ * CmdXfrBlockTPDU_T1
+ *
+ ****************************************************************************/
+static RESPONSECODE CmdXfrBlockTPDU_T1(unsigned int reader_index,
+ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[])
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ int ret;
+
+ DEBUG_COMM3("T=1: %d and %d bytes", tx_length, *rx_length);
+
+ ret = t1_transceive(&((get_ccid_slot(reader_index)) -> t1), 0,
+ tx_buffer, tx_length, rx_buffer, *rx_length);
+
+ if (ret < 0)
+ return_value = IFD_COMMUNICATION_ERROR;
+ else
+ *rx_length = ret;
+
+ return return_value;
+} /* CmdXfrBlockTPDU_T1 */
+
+
+/*****************************************************************************
+ *
+ * SetParameters
+ *
+ ****************************************************************************/
+RESPONSECODE SetParameters(unsigned int reader_index, char protocol,
+ unsigned int length, unsigned char buffer[])
+{
+ unsigned char cmd[10+length]; /* CCID + APDU buffer */
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ status_t res;
+
+ DEBUG_COMM2("length: %d bytes", length);
+
+ cmd[0] = 0x61; /* SetParameters */
+ i2dw(length, cmd+1); /* APDU length */
+ cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
+ cmd[6] = (*ccid_descriptor->pbSeq)++;
+ cmd[7] = protocol; /* bProtocolNum */
+ cmd[8] = cmd[9] = 0; /* RFU */
+
+ memcpy(cmd+10, buffer, length);
+
+ res = WritePort(reader_index, 10+length, cmd);
+ CHECK_STATUS(res)
+
+ length = sizeof(cmd);
+ res = ReadPort(reader_index, &length, cmd);
+ CHECK_STATUS(res)
+
+ if (length < STATUS_OFFSET+1)
+ {
+ DEBUG_CRITICAL2("Not enough data received: %d bytes", length);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
+ {
+ ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__); /* bError */
+ if (0x00 == cmd[ERROR_OFFSET]) /* command not supported */
+ return IFD_NOT_SUPPORTED;
+ else
+ if ((cmd[ERROR_OFFSET] >= 1) && (cmd[ERROR_OFFSET] <= 127))
+ /* a parameter is not changeable */
+ return IFD_SUCCESS;
+ else
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+} /* SetParameters */
+
+
+/*****************************************************************************
+ *
+ * isCharLevel
+ *
+ ****************************************************************************/
+int isCharLevel(int reader_index)
+{
+ return CCID_CLASS_CHARACTER == (get_ccid_descriptor(reader_index)->dwFeatures & CCID_CLASS_EXCHANGE_MASK);
+} /* isCharLevel */
+
+
+/*****************************************************************************
+ *
+ * i2dw
+ *
+ ****************************************************************************/
+static void i2dw(int value, unsigned char buffer[])
+{
+ buffer[0] = value & 0xFF;
+ buffer[1] = (value >> 8) & 0xFF;
+ buffer[2] = (value >> 16) & 0xFF;
+ buffer[3] = (value >> 24) & 0xFF;
+} /* i2dw */
+
+/*****************************************************************************
+*
+* bei2i (big endian integer to host order interger)
+*
+****************************************************************************/
+
+static unsigned int bei2i(unsigned char buffer[])
+{
+ return (buffer[0]<<24) + (buffer[1]<<16) + (buffer[2]<<8) + buffer[3];
+}
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/commands.h b/MdeModulePkg/Library/SmartCardReader/libccid/commands.h
new file mode 100644
index 0000000..c082bf2
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/commands.h
@@ -0,0 +1,64 @@
+/*
+ commands.h: Commands sent to the card
+ Copyright (C) 2003-2009 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: commands.h 6783 2013-10-24 09:36:52Z rousseau $
+ */
+
+#define SIZE_GET_SLOT_STATUS 10
+#define STATUS_OFFSET 7
+#define ERROR_OFFSET 8
+#define CHAIN_PARAMETER_OFFSET 9
+
+RESPONSECODE CmdPowerOn(unsigned int reader_index, unsigned int * nlength,
+ /*@out@*/ unsigned char buffer[], int voltage);
+
+RESPONSECODE SecurePINVerify(unsigned int reader_index,
+ unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength);
+
+RESPONSECODE SecurePINModify(unsigned int reader_index,
+ unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength);
+
+RESPONSECODE CmdEscape(unsigned int reader_index,
+ const unsigned char TxBuffer[], unsigned int TxLength,
+ unsigned char RxBuffer[], unsigned int *RxLength, unsigned int timeout);
+
+RESPONSECODE CmdPowerOff(unsigned int reader_index);
+
+RESPONSECODE CmdGetSlotStatus(unsigned int reader_index,
+ /*@out@*/ unsigned char buffer[]);
+
+RESPONSECODE CmdXfrBlock(unsigned int reader_index, unsigned int tx_length,
+ unsigned char tx_buffer[], unsigned int *rx_length,
+ unsigned char rx_buffer[], int protoccol);
+
+RESPONSECODE CCID_Transmit(unsigned int reader_index, unsigned int tx_length,
+ const unsigned char tx_buffer[], unsigned short rx_length, unsigned char bBWI);
+
+RESPONSECODE CCID_Receive(unsigned int reader_index,
+ /*@out@*/ unsigned int *rx_length,
+ /*@out@*/ unsigned char rx_buffer[], unsigned char *chain_parameter);
+
+RESPONSECODE SetParameters(unsigned int reader_index, char protocol,
+ unsigned int length, unsigned char buffer[]);
+
+int isCharLevel(int reader_index);
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/debug.c b/MdeModulePkg/Library/SmartCardReader/libccid/debug.c
new file mode 100644
index 0000000..3c8d8e5
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/debug.c
@@ -0,0 +1,157 @@
+/*
+ debug.c: log (or not) messages
+ Copyright (C) 2003-2011 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: debug.c 6975 2014-09-04 11:33:05Z rousseau $
+ */
+
+
+#include <config.h>
+#include "misc.h"
+#include "debug.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <stdlib.h>
+
+#include "strlcpycat.h"
+
+#undef LOG_TO_STDERR
+
+#ifdef LOG_TO_STDERR
+#define LOG_STREAM stderr
+#else
+#define LOG_STREAM stdout
+#endif
+
+void log_msg(const int priority, const char *fmt, ...)
+{
+ char debug_buffer[160]; /* up to 2 lines of 80 characters */
+ va_list argptr;
+ static struct timeval last_time = { 0, 0 };
+ struct timeval new_time = { 0, 0 };
+ struct timeval tmp;
+ int delta;
+ const char *color_pfx = "", *color_sfx = "";
+ const char *time_pfx = "", *time_sfx = "";
+ static int initialized = 0;
+ static int LogDoColor = 0;
+
+ if (!initialized)
+ {
+ char *term;
+
+ initialized = 1;
+ term = getenv("TERM");
+ if (term)
+ {
+ const char *terms[] = { "linux", "xterm", "xterm-color", "Eterm", "rxvt", "rxvt-unicode", "xterm-256color" };
+ unsigned int i;
+
+ /* for each known color terminal */
+ for (i = 0; i < COUNT_OF(terms); i++)
+ {
+ /* we found a supported term? */
+ if (0 == strcmp(terms[i], term))
+ {
+ LogDoColor = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (LogDoColor)
+ {
+ color_sfx = "\33[0m";
+ time_sfx = color_sfx;
+ time_pfx = "\33[36m"; /* Cyan */
+
+ switch (priority)
+ {
+ case PCSC_LOG_CRITICAL:
+ color_pfx = "\33[01;31m"; /* bright + Red */
+ break;
+
+ case PCSC_LOG_ERROR:
+ color_pfx = "\33[35m"; /* Magenta */
+ break;
+
+ case PCSC_LOG_INFO:
+ color_pfx = "\33[34m"; /* Blue */
+ break;
+
+ case PCSC_LOG_DEBUG:
+ color_pfx = ""; /* normal (black) */
+ color_sfx = "";
+ break;
+ }
+ }
+
+ gettimeofday(&new_time, NULL);
+ if (0 == last_time.tv_sec)
+ last_time = new_time;
+
+ tmp.tv_sec = new_time.tv_sec - last_time.tv_sec;
+ tmp.tv_usec = new_time.tv_usec - last_time.tv_usec;
+ if (tmp.tv_usec < 0)
+ {
+ tmp.tv_sec--;
+ tmp.tv_usec += 1000000;
+ }
+ if (tmp.tv_sec < 100)
+ delta = tmp.tv_sec * 1000000 + tmp.tv_usec;
+ else
+ delta = 99999999;
+
+ last_time = new_time;
+
+ va_start(argptr, fmt);
+ (void)vsnprintf(debug_buffer, sizeof debug_buffer, fmt, argptr);
+ va_end(argptr);
+
+ (void)fprintf(LOG_STREAM, "%s%.8d%s %s%s%s\n", time_pfx, delta, time_sfx,
+ color_pfx, debug_buffer, color_sfx);
+ fflush(LOG_STREAM);
+} /* log_msg */
+
+void log_xxd(const int priority, const char *msg, const unsigned char *buffer,
+ const int len)
+{
+ int i;
+ char *c, debug_buffer[len*3 + strlen(msg) +1];
+ size_t l;
+
+ (void)priority;
+
+ l = strlcpy(debug_buffer, msg, sizeof debug_buffer);
+ c = debug_buffer + l;
+
+ for (i = 0; i < len; ++i)
+ {
+ /* 2 hex characters, 1 space, 1 NUL : total 4 characters */
+ (void)snprintf(c, 4, "%02X ", buffer[i]);
+ c += 3;
+ }
+
+ (void)fprintf(LOG_STREAM, "%s\n", debug_buffer);
+ fflush(LOG_STREAM);
+} /* log_xxd */
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/debug.h b/MdeModulePkg/Library/SmartCardReader/libccid/debug.h
new file mode 100644
index 0000000..001e41d
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/debug.h
@@ -0,0 +1,100 @@
+/*
+ debug.h: log (or not) messages using syslog
+ Copyright (C) 2003-2008 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: debug.h 6967 2014-09-02 13:50:50Z rousseau $
+ */
+
+/*
+ * DEBUG_CRITICAL("text");
+ * log "text" if (LogLevel & DEBUG_LEVEL_CRITICAL) is TRUE
+ *
+ * DEBUG_CRITICAL2("text: %d", 1234);
+ * log "text: 1234" if (DEBUG_LEVEL_CRITICAL & DEBUG_LEVEL_CRITICAL) is TRUE
+ * the format string can be anything printf() can understand
+ *
+ * same thing for DEBUG_INFO, DEBUG_COMM and DEBUG_PERIODIC
+ *
+ * DEBUG_XXD(msg, buffer, size);
+ * log a dump of buffer if (LogLevel & DEBUG_LEVEL_COMM) is TRUE
+ *
+ */
+
+#ifndef _GCDEBUG_H_
+#define _GCDEBUG_H_
+
+/* You can't do #ifndef __FUNCTION__ */
+#if !defined(__GNUC__) && !defined(__IBMC__)
+#define __FUNCTION__ ""
+#endif
+
+extern int LogLevel;
+
+#define DEBUG_LEVEL_CRITICAL 1
+#define DEBUG_LEVEL_INFO 2
+#define DEBUG_LEVEL_COMM 4
+#define DEBUG_LEVEL_PERIODIC 8
+
+#include <debuglog.h> /* from pcsc-lite */
+
+/* DEBUG_CRITICAL */
+#define DEBUG_CRITICAL(fmt) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log1(PCSC_LOG_CRITICAL, fmt)
+
+#define DEBUG_CRITICAL2(fmt, data) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log2(PCSC_LOG_CRITICAL, fmt, data)
+
+#define DEBUG_CRITICAL3(fmt, data1, data2) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log3(PCSC_LOG_CRITICAL, fmt, data1, data2)
+
+#define DEBUG_CRITICAL4(fmt, data1, data2, data3) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log4(PCSC_LOG_CRITICAL, fmt, data1, data2, data3)
+
+#define DEBUG_CRITICAL5(fmt, data1, data2, data3, data4) if (LogLevel & DEBUG_LEVEL_CRITICAL) Log5(PCSC_LOG_CRITICAL, fmt, data1, data2, data3, data4)
+
+/* DEBUG_INFO */
+#define DEBUG_INFO1(fmt) if (LogLevel & DEBUG_LEVEL_INFO) Log1(PCSC_LOG_INFO, fmt)
+
+#define DEBUG_INFO2(fmt, data) if (LogLevel & DEBUG_LEVEL_INFO) Log2(PCSC_LOG_INFO, fmt, data)
+
+#define DEBUG_INFO3(fmt, data1, data2) if (LogLevel & DEBUG_LEVEL_INFO) Log3(PCSC_LOG_INFO, fmt, data1, data2)
+
+#define DEBUG_INFO4(fmt, data1, data2, data3) if (LogLevel & DEBUG_LEVEL_INFO) Log4(PCSC_LOG_INFO, fmt, data1, data2, data3)
+
+#define DEBUG_INFO5(fmt, data1, data2, data3, data4) if (LogLevel & DEBUG_LEVEL_INFO) Log5(PCSC_LOG_INFO, fmt, data1, data2, data3, data4)
+
+#define DEBUG_INFO_XXD(msg, buffer, size) if (LogLevel & DEBUG_LEVEL_INFO) LogXxd(PCSC_LOG_INFO, msg, buffer, size)
+
+/* DEBUG_PERIODIC */
+#define DEBUG_PERIODIC(fmt) if (LogLevel & DEBUG_LEVEL_PERIODIC) Log1(PCSC_LOG_DEBUG, fmt)
+
+#define DEBUG_PERIODIC2(fmt, data) if (LogLevel & DEBUG_LEVEL_PERIODIC) Log2(PCSC_LOG_DEBUG, fmt, data)
+
+#define DEBUG_PERIODIC3(fmt, data1, data2) if (LogLevel & DEBUG_LEVEL_PERIODIC) Log3(PCSC_LOG_DEBUG, fmt, data1, data2)
+
+/* DEBUG_COMM */
+#define DEBUG_COMM(fmt) if (LogLevel & DEBUG_LEVEL_COMM) Log1(PCSC_LOG_DEBUG, fmt)
+
+#define DEBUG_COMM2(fmt, data) if (LogLevel & DEBUG_LEVEL_COMM) Log2(PCSC_LOG_DEBUG, fmt, data)
+
+#define DEBUG_COMM3(fmt, data1, data2) if (LogLevel & DEBUG_LEVEL_COMM) Log3(PCSC_LOG_DEBUG, fmt, data1, data2)
+
+#define DEBUG_COMM4(fmt, data1, data2, data3) if (LogLevel & DEBUG_LEVEL_COMM) Log4(PCSC_LOG_DEBUG, fmt, data1, data2, data3)
+
+/* DEBUG_XXD */
+#define DEBUG_XXD(msg, buffer, size) if (LogLevel & DEBUG_LEVEL_COMM) LogXxd(PCSC_LOG_DEBUG, msg, buffer, size)
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/defs.h b/MdeModulePkg/Library/SmartCardReader/libccid/defs.h
new file mode 100644
index 0000000..50877bb
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/defs.h
@@ -0,0 +1,126 @@
+/*
+ defs.h:
+ Copyright (C) 2003-2010 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: defs.h 6926 2014-06-17 09:22:00Z rousseau $
+ */
+
+#include <pcsclite.h>
+
+#include "openct/proto-t1.h"
+
+typedef struct CCID_DESC
+{
+ /*
+ * ATR
+ */
+ int nATRLength;
+ unsigned char pcATRBuffer[MAX_ATR_SIZE];
+
+ /*
+ * Card state
+ */
+ unsigned char bPowerFlags;
+
+ /*
+ * T=1 Protocol context
+ */
+ t1_state_t t1;
+
+ /* reader name passed to IFDHCreateChannelByName() */
+#ifdef UEFI_DRIVER
+ CHAR16 *readerName;
+#else
+ char *readerName;
+#endif
+} CcidDesc;
+
+typedef enum {
+ STATUS_NO_SUCH_DEVICE = 0xF9,
+ STATUS_SUCCESS = 0xFA,
+ STATUS_UNSUCCESSFUL = 0xFB,
+ STATUS_COMM_ERROR = 0xFC,
+ STATUS_DEVICE_PROTOCOL_ERROR = 0xFD,
+ STATUS_COMM_NAK = 0xFE,
+ STATUS_SECONDARY_SLOT = 0xFF
+} status_t;
+
+/* Powerflag (used to detect quick insertion removals unnoticed by the
+ * resource manager) */
+/* Initial value */
+#define POWERFLAGS_RAZ 0x00
+/* Flag set when a power up has been requested */
+#define MASK_POWERFLAGS_PUP 0x01
+/* Flag set when a power down is requested */
+#define MASK_POWERFLAGS_PDWN 0x02
+
+/* Communication buffer size (max=adpu+Lc+data+Le)
+ * we use a 64kB for extended APDU on APDU mode readers */
+#define CMD_BUF_SIZE (4 +3 +64*1024 +3)
+
+/* Protocols */
+#define T_0 0
+#define T_1 1
+
+/* Default communication read timeout in milliseconds */
+#define DEFAULT_COM_READ_TIMEOUT (3*1000)
+
+/* DWORD type formating */
+#ifdef __APPLE__
+/* Apple defines DWORD as uint32_t */
+#define DWORD_X "%X"
+#define DWORD_D "%d"
+#else
+/* pcsc-lite defines DWORD as unsigned long */
+#define DWORD_X "%lX"
+#define DWORD_D "%ld"
+#endif
+
+/*
+ * communication ports abstraction
+ */
+#ifdef TWIN_SERIAL
+
+#define OpenPortByName OpenSerialByName
+#define OpenPort OpenSerial
+#define ClosePort CloseSerial
+#define ReadPort ReadSerial
+#define WritePort WriteSerial
+#include "ccid_serial.h"
+
+#elif defined(UEFI_DRIVER)
+
+#define OpenPortByName OpenUEFIByName
+#define OpenPort OpenUEFI
+#define ClosePort CloseUEFI
+#define ReadPort ReadUEFI
+#define WritePort WriteUEFI
+#include "ccid_uefi.h"
+
+#else
+
+#define OpenPortByName OpenUSBByName
+#define OpenPort OpenUSB
+#define ClosePort CloseUSB
+#define ReadPort ReadUSB
+#define WritePort WriteUSB
+#include "ccid_usb.h"
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c b/MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c
new file mode 100644
index 0000000..26e4400
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c
@@ -0,0 +1,2265 @@
+/*
+ ifdhandler.c: IFDH API
+ Copyright (C) 2003-2010 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/* $Id: ifdhandler.c 6977 2014-09-04 11:36:54Z rousseau $ */
+
+#include <config.h>
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifndef UEFI_DRIVER
+#include "parser.h"
+#endif
+
+#include "misc.h"
+#include <pcsclite.h>
+#include <ifdhandler.h>
+#include <reader.h>
+
+#include "ccid.h"
+#include "defs.h"
+#include "ccid_ifdhandler.h"
+#include "debug.h"
+#include "utils.h"
+#include "commands.h"
+#include "towitoko/atr.h"
+#include "towitoko/pps.h"
+#ifndef UEFI_DRIVER
+#include "strlcpycat.h"
+#endif
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+/* Array of structures to hold the ATR and other state value of each slot */
+static CcidDesc CcidSlots[CCID_DRIVER_MAX_READERS];
+
+/* global mutex */
+#ifdef HAVE_PTHREAD
+static pthread_mutex_t ifdh_context_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+int LogLevel = DEBUG_LEVEL_CRITICAL | DEBUG_LEVEL_INFO;
+int DriverOptions = 0;
+int PowerOnVoltage = VOLTAGE_5V;
+static int DebugInitialized = FALSE;
+
+/* local functions */
+static void init_driver(void);
+static void extra_egt(ATR_t *atr, _ccid_descriptor *ccid_desc, DWORD Protocol);
+static char find_baud_rate(unsigned int baudrate, unsigned int *list);
+static unsigned int T0_card_timeout(double f, double d, int TC1, int TC2,
+ int clock_frequency);
+static unsigned int T1_card_timeout(double f, double d, int TC1, int BWI,
+ int CWI, int clock_frequency);
+static int get_IFSC(ATR_t *atr, int *i);
+
+
+static RESPONSECODE CreateChannelByNameOrChannel(DWORD Lun,
+ LPSTR lpcDevice, DWORD Channel)
+{
+ RESPONSECODE return_value = IFD_SUCCESS;
+ int reader_index;
+ status_t ret;
+
+ if (! DebugInitialized)
+ init_driver();
+
+ if (lpcDevice)
+ {
+ DEBUG_INFO3("Lun: " DWORD_X ", device: %s", Lun, lpcDevice);
+ }
+ else
+ {
+ DEBUG_INFO3("Lun: " DWORD_X ", Channel: " DWORD_X, Lun, Channel);
+ }
+
+ if (-1 == (reader_index = GetNewReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ /* Reset ATR buffer */
+ CcidSlots[reader_index].nATRLength = 0;
+ *CcidSlots[reader_index].pcATRBuffer = '\0';
+
+ /* Reset PowerFlags */
+ CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
+
+ /* reader name */
+#ifdef UEFI_DRIVER
+ CcidSlots[reader_index].readerName = NULL;
+#else
+ if (lpcDevice)
+ CcidSlots[reader_index].readerName = strdup(lpcDevice);
+ else
+ CcidSlots[reader_index].readerName = strdup("no name");
+#endif
+
+#ifdef HAVE_PTHREAD
+ (void)pthread_mutex_lock(&ifdh_context_mutex);
+#endif
+
+ if (lpcDevice)
+ ret = OpenPortByName(reader_index, lpcDevice);
+ else
+ ret = OpenPort(reader_index, Channel);
+
+ if (ret != STATUS_SUCCESS)
+ {
+ DEBUG_CRITICAL("failed");
+ if (STATUS_NO_SUCH_DEVICE == ret)
+ return_value = IFD_NO_SUCH_DEVICE;
+ else
+ return_value = IFD_COMMUNICATION_ERROR;
+
+ goto error;
+ }
+ else
+ {
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+ unsigned int oldReadTimeout;
+ RESPONSECODE cmd_ret;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ /* Maybe we have a special treatment for this reader */
+ (void)ccid_open_hack_pre(reader_index);
+
+ /* Try to access the reader */
+ /* This "warm up" sequence is sometimes needed when pcscd is
+ * restarted with the reader already connected. We get some
+ * "usb_bulk_read: Resource temporarily unavailable" on the first
+ * few tries. It is an empirical hack */
+
+ /* The reader may have to start here so give it some time */
+ cmd_ret = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (IFD_NO_SUCH_DEVICE == cmd_ret)
+ {
+ return_value = cmd_ret;
+ goto error;
+ }
+
+ /* save the current read timeout computed from card capabilities */
+ oldReadTimeout = ccid_descriptor->readTimeout;
+
+ /* 100 ms just to resync the USB toggle bits */
+ ccid_descriptor->readTimeout = 100;
+
+ if ((IFD_COMMUNICATION_ERROR == CmdGetSlotStatus(reader_index, pcbuffer))
+ && (IFD_COMMUNICATION_ERROR == CmdGetSlotStatus(reader_index, pcbuffer)))
+ {
+ DEBUG_CRITICAL("failed");
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+ else
+ {
+ /* Maybe we have a special treatment for this reader */
+ return_value = ccid_open_hack_post(reader_index);
+ if (return_value != IFD_SUCCESS)
+ {
+ DEBUG_CRITICAL("failed");
+ }
+ }
+
+ /* set back the old timeout */
+ ccid_descriptor->readTimeout = oldReadTimeout;
+ }
+
+error:
+#ifdef HAVE_PTHREAD
+ (void)pthread_mutex_unlock(&ifdh_context_mutex);
+#endif
+
+ if (return_value != IFD_SUCCESS)
+ {
+ /* release the allocated resources */
+#ifndef UEFI_DRIVER
+ free(CcidSlots[reader_index].readerName);
+#endif
+ ReleaseReaderIndex(reader_index);
+ }
+
+ return return_value;
+} /* CreateChannelByNameOrChannel */
+
+
+EXTERNAL RESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR lpcDevice)
+{
+ return CreateChannelByNameOrChannel(Lun, lpcDevice, -1);
+}
+
+EXTERNAL RESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel)
+{
+ /*
+ * Lun - Logical Unit Number, use this for multiple card slots or
+ * multiple readers. 0xXXXXYYYY - XXXX multiple readers, YYYY multiple
+ * slots. The resource manager will set these automatically. By
+ * default the resource manager loads a new instance of the driver so
+ * if your reader does not have more than one smartcard slot then
+ * ignore the Lun in all the functions. Future versions of PC/SC might
+ * support loading multiple readers through one instance of the driver
+ * in which XXXX would be important to implement if you want this.
+ */
+
+ /*
+ * Channel - Channel ID. This is denoted by the following: 0x000001 -
+ * /dev/pcsc/1 0x000002 - /dev/pcsc/2 0x000003 - /dev/pcsc/3
+ *
+ * USB readers may choose to ignore this parameter and query the bus
+ * for the particular reader.
+ */
+
+ /*
+ * This function is required to open a communications channel to the
+ * port listed by Channel. For example, the first serial reader on
+ * COM1 would link to /dev/pcsc/1 which would be a sym link to
+ * /dev/ttyS0 on some machines This is used to help with intermachine
+ * independance.
+ *
+ * Once the channel is opened the reader must be in a state in which
+ * it is possible to query IFDHICCPresence() for card status.
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_COMMUNICATION_ERROR
+ */
+ return CreateChannelByNameOrChannel(Lun, NULL, Channel);
+} /* IFDHCreateChannel */
+
+
+EXTERNAL RESPONSECODE IFDHCloseChannel(DWORD Lun)
+{
+ /*
+ * This function should close the reader communication channel for the
+ * particular reader. Prior to closing the communication channel the
+ * reader should make sure the card is powered down and the terminal
+ * is also powered down.
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_COMMUNICATION_ERROR
+ */
+ int reader_index;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName,
+ Lun);
+
+ /* Restore the default timeout
+ * No need to wait too long if the reader disapeared */
+ get_ccid_descriptor(reader_index)->readTimeout = DEFAULT_COM_READ_TIMEOUT;
+
+ (void)CmdPowerOff(reader_index);
+ /* No reader status check, if it failed, what can you do ? :) */
+
+#ifdef HAVE_PTHREAD
+ (void)pthread_mutex_lock(&ifdh_context_mutex);
+#endif
+
+ (void)ClosePort(reader_index);
+ ReleaseReaderIndex(reader_index);
+
+#ifndef UEFI_DRIVER
+ free(CcidSlots[reader_index].readerName);
+#endif
+ memset(&CcidSlots[reader_index], 0, sizeof(CcidSlots[reader_index]));
+
+#ifdef HAVE_PTHREAD
+ (void)pthread_mutex_unlock(&ifdh_context_mutex);
+#endif
+
+ return IFD_SUCCESS;
+} /* IFDHCloseChannel */
+
+
+#if !defined(TWIN_SERIAL) && !defined(UEFI_DRIVER)
+static RESPONSECODE IFDHPolling(DWORD Lun, int timeout)
+{
+ int reader_index;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ /* log only if DEBUG_LEVEL_PERIODIC is set */
+ if (LogLevel & DEBUG_LEVEL_PERIODIC)
+ DEBUG_INFO4("%s (lun: " DWORD_X ") %d ms",
+ CcidSlots[reader_index].readerName, Lun, timeout);
+
+ return InterruptRead(reader_index, timeout);
+}
+
+/* on an ICCD device the card is always inserted
+ * so no card movement will ever happen: just do nothing */
+static RESPONSECODE IFDHSleep(DWORD Lun, int timeout)
+{
+ int reader_index;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO4("%s (lun: " DWORD_X ") %d ms",
+ CcidSlots[reader_index].readerName, Lun, timeout);
+
+ /* just sleep for 5 seconds since the polling thread is NOT killable
+ * so pcscd event thread must loop to exit cleanly
+ *
+ * Once the driver (libusb in fact) will support
+ * TAG_IFD_POLLING_THREAD_KILLABLE then we could use a much longer delay
+ * and be killed before pcscd exits
+ */
+ (void)usleep(timeout);
+ return IFD_SUCCESS;
+}
+
+static RESPONSECODE IFDHStopPolling(DWORD Lun)
+{
+ int reader_index;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO3("%s (lun: " DWORD_X ")",
+ CcidSlots[reader_index].readerName, Lun);
+
+ (void)InterruptStop(reader_index);
+ return IFD_SUCCESS;
+}
+#endif
+
+
+EXTERNAL RESPONSECODE IFDHGetCapabilities(DWORD Lun, DWORD Tag,
+ PDWORD Length, PUCHAR Value)
+{
+ /*
+ * This function should get the slot/card capabilities for a
+ * particular slot/card specified by Lun. Again, if you have only 1
+ * card slot and don't mind loading a new driver for each reader then
+ * ignore Lun.
+ *
+ * Tag - the tag for the information requested example: TAG_IFD_ATR -
+ * return the Atr and it's size (required). these tags are defined in
+ * ifdhandler.h
+ *
+ * Length - the length of the returned data Value - the value of the
+ * data
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_ERROR_TAG
+ */
+ int reader_index;
+ RESPONSECODE return_value = IFD_SUCCESS;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO4("tag: 0x" DWORD_X ", %s (lun: " DWORD_X ")", Tag,
+ CcidSlots[reader_index].readerName, Lun);
+
+ switch (Tag)
+ {
+ case TAG_IFD_ATR:
+ case SCARD_ATTR_ATR_STRING:
+ /* If Length is not zero, powerICC has been performed.
+ * Otherwise, return NULL pointer
+ * Buffer size is stored in *Length */
+ if ((int)*Length >= CcidSlots[reader_index].nATRLength)
+ {
+ *Length = CcidSlots[reader_index].nATRLength;
+
+ memcpy(Value, CcidSlots[reader_index].pcATRBuffer, *Length);
+ }
+ else
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ break;
+
+ case SCARD_ATTR_ICC_INTERFACE_STATUS:
+ *Length = 1;
+ if (IFD_ICC_PRESENT == IFDHICCPresence(Lun))
+ /* nonzero if contact is active */
+ *Value = 1;
+ else
+ /* smart card electrical contact is not active */
+ *Value = 0;
+ break;
+
+ case SCARD_ATTR_ICC_PRESENCE:
+ *Length = 1;
+ /* Single byte indicating smart card presence:
+ * 0 = not present
+ * 1 = card present but not swallowed (applies only if
+ * reader supports smart card swallowing)
+ * 2 = card present (and swallowed if reader supports smart
+ * card swallowing)
+ * 4 = card confiscated. */
+ if (IFD_ICC_PRESENT == IFDHICCPresence(Lun))
+ /* Card present */
+ *Value = 2;
+ else
+ /* Not present */
+ *Value = 0;
+ break;
+
+#ifdef HAVE_PTHREAD
+ case TAG_IFD_SIMULTANEOUS_ACCESS:
+ if (*Length >= 1)
+ {
+ *Length = 1;
+ *Value = CCID_DRIVER_MAX_READERS;
+ }
+ else
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ break;
+
+ case TAG_IFD_THREAD_SAFE:
+ if (*Length >= 1)
+ {
+ *Length = 1;
+#ifdef __APPLE__
+ *Value = 0; /* Apple pcscd is bogus (rdar://problem/5697388) */
+#else
+ *Value = 1; /* Can talk to multiple readers at the same time */
+#endif
+ }
+ else
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ break;
+#endif
+
+ case TAG_IFD_SLOTS_NUMBER:
+ if (*Length >= 1)
+ {
+ *Length = 1;
+ *Value = 1 + get_ccid_descriptor(reader_index) -> bMaxSlotIndex;
+#ifdef USE_COMPOSITE_AS_MULTISLOT
+ {
+ /* On MacOS X or Linux+libusb we can simulate a
+ * composite device with 2 CCID interfaces by a
+ * multi-slot reader */
+ int readerID = get_ccid_descriptor(reader_index) -> readerID;
+
+ if ((GEMALTOPROXDU == readerID) || (GEMALTOPROXSU == readerID))
+ *Value = 2;
+ }
+#endif
+ DEBUG_INFO2("Reader supports %d slot(s)", *Value);
+ }
+ else
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ break;
+
+ case TAG_IFD_SLOT_THREAD_SAFE:
+ if (*Length >= 1)
+ {
+ *Length = 1;
+ *Value = 0; /* Can NOT talk to multiple slots at the same time */
+ }
+ else
+ return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
+ break;
+
+ case SCARD_ATTR_VENDOR_IFD_VERSION:
+ {
+ int IFD_bcdDevice = get_ccid_descriptor(reader_index)->IFD_bcdDevice;
+
+ /* Vendor-supplied interface device version (DWORD in the form
+ * 0xMMmmbbbb where MM = major version, mm = minor version, and
+ * bbbb = build number). */
+ *Length = 4;
+ if (Value)
+ *(uint32_t *)Value = IFD_bcdDevice << 16;
+ }
+ break;
+
+#ifndef UEFI_DRIVER
+ case SCARD_ATTR_VENDOR_NAME:
+ {
+ const char *sIFD_iManufacturer = get_ccid_descriptor(reader_index) -> sIFD_iManufacturer;
+
+ if (sIFD_iManufacturer)
+ {
+ strlcpy((char *)Value, sIFD_iManufacturer, *Length);
+ *Length = strlen((char *)Value) +1;
+ }
+ else
+ {
+ /* not supported */
+ *Length = 0;
+ }
+ }
+ break;
+#endif
+
+ case SCARD_ATTR_MAXINPUT:
+ *Length = sizeof(uint32_t);
+ if (Value)
+ *(uint32_t *)Value = get_ccid_descriptor(reader_index) -> dwMaxCCIDMessageLength -10;
+ break;
+
+#if !defined(TWIN_SERIAL) && !defined(UEFI_DRIVER)
+ case TAG_IFD_POLLING_THREAD_WITH_TIMEOUT:
+ {
+ _ccid_descriptor *ccid_desc;
+
+ /* default value: not supported */
+ *Length = 0;
+
+ ccid_desc = get_ccid_descriptor(reader_index);
+
+ /* CCID and not ICCD */
+ if ((PROTOCOL_CCID == ccid_desc -> bInterfaceProtocol)
+ /* 3 end points */
+ && (3 == ccid_desc -> bNumEndpoints))
+ {
+ *Length = sizeof(void *);
+ if (Value)
+ *(void **)Value = IFDHPolling;
+ }
+
+ if ((PROTOCOL_ICCD_A == ccid_desc->bInterfaceProtocol)
+ || (PROTOCOL_ICCD_B == ccid_desc->bInterfaceProtocol))
+ {
+ *Length = sizeof(void *);
+ if (Value)
+ *(void **)Value = IFDHSleep;
+ }
+ }
+ break;
+
+ case TAG_IFD_POLLING_THREAD_KILLABLE:
+ {
+ _ccid_descriptor *ccid_desc;
+
+ /* default value: not supported */
+ *Length = 0;
+
+ ccid_desc = get_ccid_descriptor(reader_index);
+ if ((PROTOCOL_ICCD_A == ccid_desc->bInterfaceProtocol)
+ || (PROTOCOL_ICCD_B == ccid_desc->bInterfaceProtocol))
+ {
+ *Length = 1; /* 1 char */
+ if (Value)
+ *Value = 1; /* TRUE */
+ }
+ }
+ break;
+
+ case TAG_IFD_STOP_POLLING_THREAD:
+ {
+ _ccid_descriptor *ccid_desc;
+
+ /* default value: not supported */
+ *Length = 0;
+
+ ccid_desc = get_ccid_descriptor(reader_index);
+ /* CCID and not ICCD */
+ if ((PROTOCOL_CCID == ccid_desc -> bInterfaceProtocol)
+ /* 3 end points */
+ && (3 == ccid_desc -> bNumEndpoints))
+ {
+ *Length = sizeof(void *);
+ if (Value)
+ *(void **)Value = IFDHStopPolling;
+ }
+ }
+ break;
+#endif
+
+#ifndef UEFI_DRIVER
+ case SCARD_ATTR_VENDOR_IFD_SERIAL_NO:
+ {
+ _ccid_descriptor *ccid_desc;
+
+ ccid_desc = get_ccid_descriptor(reader_index);
+ if (ccid_desc->sIFD_serial_number)
+ {
+ strlcpy((char *)Value, ccid_desc->sIFD_serial_number, *Length);
+ *Length = strlen((char *)Value);
+ }
+ else
+ {
+ /* not supported */
+ *Length = 0;
+ }
+ }
+ break;
+#endif
+
+ default:
+ return_value = IFD_ERROR_TAG;
+ }
+
+ return return_value;
+} /* IFDHGetCapabilities */
+
+
+EXTERNAL RESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag,
+ /*@unused@*/ DWORD Length, /*@unused@*/ PUCHAR Value)
+{
+ /*
+ * This function should set the slot/card capabilities for a
+ * particular slot/card specified by Lun. Again, if you have only 1
+ * card slot and don't mind loading a new driver for each reader then
+ * ignore Lun.
+ *
+ * Tag - the tag for the information needing set
+ *
+ * Length - the length of the returned data Value - the value of the
+ * data
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_ERROR_TAG IFD_ERROR_SET_FAILURE
+ * IFD_ERROR_VALUE_READ_ONLY
+ */
+
+ (void)Length;
+ (void)Value;
+
+ int reader_index;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO4("tag: 0x" DWORD_X ", %s (lun: " DWORD_X ")", Tag,
+ CcidSlots[reader_index].readerName, Lun);
+
+ return IFD_NOT_SUPPORTED;
+} /* IFDHSetCapabilities */
+
+
+EXTERNAL RESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol,
+ UCHAR Flags, UCHAR PTS1, UCHAR PTS2, UCHAR PTS3)
+{
+ /*
+ * This function should set the PTS of a particular card/slot using
+ * the three PTS parameters sent
+ *
+ * Protocol - SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1
+ * Flags - Logical OR of possible values:
+ * IFD_NEGOTIATE_PTS1
+ * IFD_NEGOTIATE_PTS2
+ * IFD_NEGOTIATE_PTS3
+ * to determine which PTS values to negotiate.
+ * PTS1,PTS2,PTS3 - PTS Values.
+ *
+ * returns:
+ * IFD_SUCCESS
+ * IFD_ERROR_PTS_FAILURE
+ * IFD_COMMUNICATION_ERROR
+ * IFD_PROTOCOL_NOT_SUPPORTED
+ */
+
+ BYTE pps[PPS_MAX_LENGTH];
+ ATR_t atr;
+ unsigned int len;
+ int convention;
+ int reader_index;
+ int atr_ret;
+
+ /* Set ccid desc params */
+ CcidDesc *ccid_slot;
+ _ccid_descriptor *ccid_desc;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO4("protocol T=" DWORD_D ", %s (lun: " DWORD_X ")",
+ Protocol-SCARD_PROTOCOL_T0, CcidSlots[reader_index].readerName, Lun);
+
+ /* Set to zero buffer */
+ memset(pps, 0, sizeof(pps));
+ memset(&atr, 0, sizeof(atr));
+
+ /* Get ccid params */
+ ccid_slot = get_ccid_slot(reader_index);
+ ccid_desc = get_ccid_descriptor(reader_index);
+
+ /* Do not send CCID command SetParameters or PPS to the CCID
+ * The CCID will do this himself */
+ if (ccid_desc->dwFeatures & CCID_CLASS_AUTO_PPS_PROP)
+ {
+ DEBUG_COMM2("Timeout: %d ms", ccid_desc->readTimeout);
+ goto end;
+ }
+
+ /* Get ATR of the card */
+ atr_ret = ATR_InitFromArray(&atr, ccid_slot->pcATRBuffer,
+ ccid_slot->nATRLength);
+ if (ATR_MALFORMED == atr_ret)
+ return IFD_PROTOCOL_NOT_SUPPORTED;
+
+ /* Apply Extra EGT patch for bogus cards */
+ extra_egt(&atr, ccid_desc, Protocol);
+
+ if (SCARD_PROTOCOL_T0 == Protocol)
+ pps[1] |= ATR_PROTOCOL_TYPE_T0;
+ else
+ if (SCARD_PROTOCOL_T1 == Protocol)
+ pps[1] |= ATR_PROTOCOL_TYPE_T1;
+ else
+ return IFD_PROTOCOL_NOT_SUPPORTED;
+
+ /* TA2 present -> specific mode */
+ if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present)
+ {
+ if (pps[1] != (atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F))
+ {
+ /* wrong protocol */
+ DEBUG_COMM3("Specific mode in T=%d and T=%d requested",
+ atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F, pps[1]);
+
+ return IFD_PROTOCOL_NOT_SUPPORTED;
+ }
+ }
+
+ /* TCi (i>2) indicates CRC instead of LRC */
+ if (SCARD_PROTOCOL_T1 == Protocol)
+ {
+ t1_state_t *t1 = &(ccid_slot -> t1);
+ int i;
+
+ /* TCi (i>2) present? */
+ for (i=2; i<ATR_MAX_PROTOCOLS; i++)
+ if (atr.ib[i][ATR_INTERFACE_BYTE_TC].present)
+ {
+ if (0 == atr.ib[i][ATR_INTERFACE_BYTE_TC].value)
+ {
+ DEBUG_COMM("Use LRC");
+ (void)t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC, 0);
+ }
+ else
+ if (1 == atr.ib[i][ATR_INTERFACE_BYTE_TC].value)
+ {
+ DEBUG_COMM("Use CRC");
+ (void)t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_CRC, 0);
+ }
+ else
+ DEBUG_COMM2("Wrong value for TCi: %d",
+ atr.ib[i][ATR_INTERFACE_BYTE_TC].value);
+
+ /* only the first TCi (i>2) must be used */
+ break;
+ }
+ }
+
+ /* PTS1? */
+ if (Flags & IFD_NEGOTIATE_PTS1)
+ {
+ /* just use the value passed in argument */
+ pps[1] |= 0x10; /* PTS1 presence */
+ pps[2] = PTS1;
+ }
+ else
+ {
+ /* TA1 present */
+ if (atr.ib[0][ATR_INTERFACE_BYTE_TA].present)
+ {
+ unsigned int card_baudrate;
+ unsigned int default_baudrate;
+ double f, d;
+
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
+
+ /* may happen with non ISO cards */
+ if ((0 == f) || (0 == d))
+ {
+ /* values for TA1=11 */
+ f = 372;
+ d = 1;
+ }
+
+ /* Baudrate = f x D/F */
+ card_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock
+ * d / f);
+
+ default_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock
+ * ATR_DEFAULT_D / ATR_DEFAULT_F);
+
+ /* if the card does not try to lower the default speed */
+ if ((card_baudrate > default_baudrate)
+ /* and the reader is fast enough */
+ && (card_baudrate <= ccid_desc->dwMaxDataRate))
+ {
+ /* the reader has no baud rates table */
+ if ((NULL == ccid_desc->arrayOfSupportedDataRates)
+ /* or explicitely support it */
+ || find_baud_rate(card_baudrate,
+ ccid_desc->arrayOfSupportedDataRates))
+ {
+ pps[1] |= 0x10; /* PTS1 presence */
+ pps[2] = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
+
+ DEBUG_COMM2("Set speed to %d bauds", card_baudrate);
+ }
+ else
+ {
+ DEBUG_COMM2("Reader does not support %d bauds",
+ card_baudrate);
+
+ /* TA2 present -> specific mode: the card is supporting
+ * only the baud rate specified in TA1 but reader does not
+ * support this value. Reject the card. */
+ if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present)
+ return IFD_COMMUNICATION_ERROR;
+ }
+ }
+ else
+ {
+ /* the card is too fast for the reader */
+ if ((card_baudrate > ccid_desc->dwMaxDataRate +2)
+ /* but TA1 <= 97 */
+ && (atr.ib[0][ATR_INTERFACE_BYTE_TA].value <= 0x97)
+ /* and the reader has a baud rate table */
+ && ccid_desc->arrayOfSupportedDataRates)
+ {
+ unsigned char old_TA1;
+
+ old_TA1 = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
+ while (atr.ib[0][ATR_INTERFACE_BYTE_TA].value > 0x94)
+ {
+ /* use a lower TA1 */
+ atr.ib[0][ATR_INTERFACE_BYTE_TA].value--;
+
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
+
+ /* Baudrate = f x D/F */
+ card_baudrate = (unsigned int) (1000 *
+ ccid_desc->dwDefaultClock * d / f);
+
+ if (find_baud_rate(card_baudrate,
+ ccid_desc->arrayOfSupportedDataRates))
+ {
+ pps[1] |= 0x10; /* PTS1 presence */
+ pps[2] = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
+
+ DEBUG_COMM2("Set adapted speed to %d bauds",
+ card_baudrate);
+
+ break;
+ }
+ }
+
+ /* restore original TA1 value */
+ atr.ib[0][ATR_INTERFACE_BYTE_TA].value = old_TA1;
+ }
+ }
+ }
+ }
+
+ /* PTS2? */
+ if (Flags & IFD_NEGOTIATE_PTS2)
+ {
+ pps[1] |= 0x20; /* PTS2 presence */
+ pps[3] = PTS2;
+ }
+
+ /* PTS3? */
+ if (Flags & IFD_NEGOTIATE_PTS3)
+ {
+ pps[1] |= 0x40; /* PTS3 presence */
+ pps[4] = PTS3;
+ }
+
+ /* Generate PPS */
+ pps[0] = 0xFF;
+
+ /* Automatic PPS made by the ICC? */
+ if ((! (ccid_desc->dwFeatures & CCID_CLASS_AUTO_PPS_CUR))
+ /* TA2 absent: negociable mode */
+ && (! atr.ib[1][ATR_INTERFACE_BYTE_TA].present))
+ {
+ int default_protocol;
+
+ ATR_GetDefaultProtocol(&atr, &default_protocol, NULL);
+
+ /* if the requested protocol is not the default one
+ * or a TA1/PPS1 is present */
+ if (((pps[1] & 0x0F) != default_protocol) || (PPS_HAS_PPS1(pps)))
+ {
+#ifdef O2MICRO_OZ776_PATCH
+ if ((OZ776 == ccid_desc->readerID)
+ || (OZ776_7772 == ccid_desc->readerID))
+ {
+ /* convert from ATR_PROTOCOL_TYPE_T? to SCARD_PROTOCOL_T? */
+ Protocol = default_protocol +
+ (SCARD_PROTOCOL_T0 - ATR_PROTOCOL_TYPE_T0);
+ DEBUG_INFO2("PPS not supported on O2Micro readers. Using T=" DWORD_D,
+ Protocol - SCARD_PROTOCOL_T0);
+ }
+ else
+#endif
+ if (PPS_Exchange(reader_index, pps, &len, &pps[2]) != PPS_OK)
+ {
+ DEBUG_INFO1("PPS_Exchange Failed");
+
+ return IFD_ERROR_PTS_FAILURE;
+ }
+ }
+ }
+
+ /* Now we must set the reader parameters */
+ (void)ATR_GetConvention(&atr, &convention);
+
+ /* specific mode and implicit parameters? (b5 of TA2) */
+ if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present
+ && (atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x10))
+ return IFD_COMMUNICATION_ERROR;
+
+ /* T=1 */
+ if (SCARD_PROTOCOL_T1 == Protocol)
+ {
+ BYTE param[] = {
+ 0x11, /* Fi/Di */
+ 0x10, /* TCCKS */
+ 0x00, /* GuardTime */
+ 0x4D, /* BWI/CWI */
+ 0x00, /* ClockStop */
+ 0x20, /* IFSC */
+ 0x00 /* NADValue */
+ };
+ int i;
+ t1_state_t *t1 = &(ccid_slot -> t1);
+ RESPONSECODE ret;
+ double f, d;
+ int ifsc;
+
+ /* TA1 is not default */
+ if (PPS_HAS_PPS1(pps))
+ param[0] = pps[2];
+
+ /* CRC checksum? */
+ if (2 == t1->rc_bytes)
+ param[1] |= 0x01;
+
+ /* the CCID should ignore this bit */
+ if (ATR_CONVENTION_INVERSE == convention)
+ param[1] |= 0x02;
+
+ /* get TC1 Extra guard time */
+ if (atr.ib[0][ATR_INTERFACE_BYTE_TC].present)
+ param[2] = atr.ib[0][ATR_INTERFACE_BYTE_TC].value;
+
+ /* TBi (i>2) present? BWI/CWI */
+ for (i=2; i<ATR_MAX_PROTOCOLS; i++)
+ if (atr.ib[i][ATR_INTERFACE_BYTE_TB].present)
+ {
+ DEBUG_COMM3("BWI/CWI (TB%d) present: 0x%02X", i+1,
+ atr.ib[i][ATR_INTERFACE_BYTE_TB].value);
+ param[3] = atr.ib[i][ATR_INTERFACE_BYTE_TB].value;
+
+ {
+ /* Hack for OpenPGP card */
+ unsigned char openpgp_atr[] = { 0x3B, 0xFA, 0x13,
+ 0x00, 0xFF, 0x81, 0x31, 0x80, 0x45, 0x00, 0x31,
+ 0xC1, 0x73, 0xC0, 0x01, 0x00, 0x00, 0x90, 0x00, 0xB1 };
+
+ if (0 == memcmp(ccid_slot->pcATRBuffer, openpgp_atr,
+ ccid_slot->nATRLength))
+ /* change BWI from 4 to 7 to increase BWT from
+ * 1.4s to 11s and avoid a timeout during on
+ * board key generation (bogus card) */
+ {
+ param[3] = 0x75;
+ DEBUG_COMM2("OpenPGP hack, using 0x%02X", param[3]);
+ }
+ }
+
+ /* only the first TBi (i>2) must be used */
+ break;
+ }
+
+ /* compute communication timeout */
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
+ ccid_desc->readTimeout = T1_card_timeout(f, d, param[2],
+ (param[3] & 0xF0) >> 4 /* BWI */, param[3] & 0x0F /* CWI */,
+ ccid_desc->dwDefaultClock);
+
+ ifsc = get_IFSC(&atr, &i);
+ if (ifsc > 0)
+ {
+ DEBUG_COMM3("IFSC (TA%d) present: %d", i, ifsc);
+ param[5] = ifsc;
+ }
+
+ DEBUG_COMM2("Timeout: %d ms", ccid_desc->readTimeout);
+
+ ret = SetParameters(reader_index, 1, sizeof(param), param);
+ if (IFD_SUCCESS != ret)
+ return ret;
+ }
+ else
+ /* T=0 */
+ {
+ BYTE param[] = {
+ 0x11, /* Fi/Di */
+ 0x00, /* TCCKS */
+ 0x00, /* GuardTime */
+ 0x0A, /* WaitingInteger */
+ 0x00 /* ClockStop */
+ };
+ RESPONSECODE ret;
+ double f, d;
+
+ /* TA1 is not default */
+ if (PPS_HAS_PPS1(pps))
+ param[0] = pps[2];
+
+ if (ATR_CONVENTION_INVERSE == convention)
+ param[1] |= 0x02;
+
+ /* get TC1 Extra guard time */
+ if (atr.ib[0][ATR_INTERFACE_BYTE_TC].present)
+ param[2] = atr.ib[0][ATR_INTERFACE_BYTE_TC].value;
+
+ /* TC2 WWT */
+ if (atr.ib[1][ATR_INTERFACE_BYTE_TC].present)
+ param[3] = atr.ib[1][ATR_INTERFACE_BYTE_TC].value;
+
+ /* compute communication timeout */
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
+ (void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
+
+ ccid_desc->readTimeout = T0_card_timeout(f, d, param[2] /* TC1 */,
+ param[3] /* TC2 */, ccid_desc->dwDefaultClock);
+
+ DEBUG_COMM2("Communication timeout: %d ms", ccid_desc->readTimeout);
+
+ ret = SetParameters(reader_index, 0, sizeof(param), param);
+ if (IFD_SUCCESS != ret)
+ return ret;
+ }
+
+ /* set IFSC & IFSD in T=1 */
+ if (SCARD_PROTOCOL_T1 == Protocol)
+ {
+ t1_state_t *t1 = &(ccid_slot -> t1);
+ int i, ifsc;
+
+ ifsc = get_IFSC(&atr, &i);
+ if (ifsc > 0)
+ {
+ DEBUG_COMM3("IFSC (TA%d) present: %d", i, ifsc);
+ (void)t1_set_param(t1, IFD_PROTOCOL_T1_IFSC, ifsc);
+ }
+
+ /* IFSD not negociated by the reader? */
+ if (! (ccid_desc->dwFeatures & CCID_CLASS_AUTO_IFSD))
+ {
+ DEBUG_COMM2("Negociate IFSD at %d", ccid_desc -> dwMaxIFSD);
+ if (t1_negotiate_ifsd(t1, 0, ccid_desc -> dwMaxIFSD) < 0)
+ return IFD_COMMUNICATION_ERROR;
+ }
+ (void)t1_set_param(t1, IFD_PROTOCOL_T1_IFSD, ccid_desc -> dwMaxIFSD);
+
+ DEBUG_COMM3("T=1: IFSC=%d, IFSD=%d", t1->ifsc, t1->ifsd);
+ }
+
+end:
+ /* store used protocol for use by the secure commands (verify/change PIN) */
+ ccid_desc->cardProtocol = Protocol;
+
+ return IFD_SUCCESS;
+} /* IFDHSetProtocolParameters */
+
+
+EXTERNAL RESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action,
+ PUCHAR Atr, PDWORD AtrLength)
+{
+ /*
+ * This function controls the power and reset signals of the smartcard
+ * reader at the particular reader/slot specified by Lun.
+ *
+ * Action - Action to be taken on the card.
+ *
+ * IFD_POWER_UP - Power and reset the card if not done so (store the
+ * ATR and return it and it's length).
+ *
+ * IFD_POWER_DOWN - Power down the card if not done already
+ * (Atr/AtrLength should be zero'd)
+ *
+ * IFD_RESET - Perform a quick reset on the card. If the card is not
+ * powered power up the card. (Store and return the Atr/Length)
+ *
+ * Atr - Answer to Reset of the card. The driver is responsible for
+ * caching this value in case IFDHGetCapabilities is called requesting
+ * the ATR and it's length. This should not exceed MAX_ATR_SIZE.
+ *
+ * AtrLength - Length of the Atr. This should not exceed
+ * MAX_ATR_SIZE.
+ *
+ * Notes:
+ *
+ * Memory cards without an ATR should return IFD_SUCCESS on reset but
+ * the Atr should be zero'd and the length should be zero
+ *
+ * Reset errors should return zero for the AtrLength and return
+ * IFD_ERROR_POWER_ACTION.
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_ERROR_POWER_ACTION IFD_COMMUNICATION_ERROR
+ * IFD_NOT_SUPPORTED
+ */
+
+ unsigned int nlength;
+ RESPONSECODE return_value = IFD_SUCCESS;
+ unsigned char pcbuffer[10+MAX_ATR_SIZE];
+ int reader_index;
+#ifndef NO_LOG
+ const char *actions[] = { "PowerUp", "PowerDown", "Reset" };
+#endif
+ unsigned int oldReadTimeout;
+ _ccid_descriptor *ccid_descriptor;
+
+ /* By default, assume it won't work :) */
+ *AtrLength = 0;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+#ifdef UEFI_DRIVER
+ DEBUG_INFO4("action: %a, %s (lun: " DWORD_X ")",
+#else
+ DEBUG_INFO4("action: %s, %s (lun: " DWORD_X ")",
+#endif
+ actions[Action-IFD_POWER_UP], CcidSlots[reader_index].readerName, Lun);
+
+ switch (Action)
+ {
+ case IFD_POWER_DOWN:
+ /* Clear ATR buffer */
+ CcidSlots[reader_index].nATRLength = 0;
+ *CcidSlots[reader_index].pcATRBuffer = '\0';
+
+ /* Memorise the request */
+ CcidSlots[reader_index].bPowerFlags |= MASK_POWERFLAGS_PDWN;
+
+ /* send the command */
+ if (IFD_SUCCESS != CmdPowerOff(reader_index))
+ {
+ DEBUG_CRITICAL("PowerDown failed");
+ return_value = IFD_ERROR_POWER_ACTION;
+ goto end;
+ }
+
+ /* clear T=1 context */
+ t1_release(&(get_ccid_slot(reader_index) -> t1));
+ break;
+
+ case IFD_POWER_UP:
+ case IFD_RESET:
+ /* save the current read timeout computed from card capabilities */
+ ccid_descriptor = get_ccid_descriptor(reader_index);
+ oldReadTimeout = ccid_descriptor->readTimeout;
+
+ /* The German eID card is bogus and need to be powered off
+ * before a power on */
+ if (KOBIL_IDTOKEN == ccid_descriptor -> readerID)
+ {
+ /* send the command */
+ if (IFD_SUCCESS != CmdPowerOff(reader_index))
+ {
+ DEBUG_CRITICAL("PowerDown failed");
+ return_value = IFD_ERROR_POWER_ACTION;
+ goto end;
+ }
+ }
+
+ /* use a very long timeout since the card can use up to
+ * (9600+12)*33 ETU in total
+ * 12 ETU per byte
+ * 9600 ETU max between each byte
+ * 33 bytes max for ATR
+ * 1 ETU = 372 cycles during ATR
+ * with a 4 MHz clock => 29 seconds
+ */
+ ccid_descriptor->readTimeout = 60*1000;
+
+ nlength = sizeof(pcbuffer);
+ return_value = CmdPowerOn(reader_index, &nlength, pcbuffer,
+ PowerOnVoltage);
+
+ /* set back the old timeout */
+ ccid_descriptor->readTimeout = oldReadTimeout;
+
+ if (return_value != IFD_SUCCESS)
+ {
+ /* used by GemCore SIM PRO: no card is present */
+ if (GEMCORESIMPRO == ccid_descriptor -> readerID)
+ get_ccid_descriptor(reader_index)->dwSlotStatus
+ = IFD_ICC_NOT_PRESENT;
+
+ DEBUG_CRITICAL("PowerUp failed");
+ return_value = IFD_ERROR_POWER_ACTION;
+ goto end;
+ }
+
+ /* Power up successful, set state variable to memorise it */
+ CcidSlots[reader_index].bPowerFlags |= MASK_POWERFLAGS_PUP;
+ CcidSlots[reader_index].bPowerFlags &= ~MASK_POWERFLAGS_PDWN;
+
+ /* Reset is returned, even if TCK is wrong */
+ CcidSlots[reader_index].nATRLength = *AtrLength =
+ (nlength < MAX_ATR_SIZE) ? nlength : MAX_ATR_SIZE;
+ memcpy(Atr, pcbuffer, *AtrLength);
+ memcpy(CcidSlots[reader_index].pcATRBuffer, pcbuffer, *AtrLength);
+
+ /* initialise T=1 context */
+ (void)t1_init(&(get_ccid_slot(reader_index) -> t1), reader_index);
+ break;
+
+ default:
+ DEBUG_CRITICAL("Action not supported");
+ return_value = IFD_NOT_SUPPORTED;
+ }
+end:
+
+ return return_value;
+} /* IFDHPowerICC */
+
+
+EXTERNAL RESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci,
+ PUCHAR TxBuffer, DWORD TxLength,
+ PUCHAR RxBuffer, PDWORD RxLength, /*@unused@*/ PSCARD_IO_HEADER RecvPci)
+{
+ /*
+ * This function performs an APDU exchange with the card/slot
+ * specified by Lun. The driver is responsible for performing any
+ * protocol specific exchanges such as T=0/1 ... differences. Calling
+ * this function will abstract all protocol differences.
+ *
+ * SendPci Protocol - 0, 1, .... 14 Length - Not used.
+ *
+ * TxBuffer - Transmit APDU example (0x00 0xA4 0x00 0x00 0x02 0x3F
+ * 0x00) TxLength - Length of this buffer. RxBuffer - Receive APDU
+ * example (0x61 0x14) RxLength - Length of the received APDU. This
+ * function will be passed the size of the buffer of RxBuffer and this
+ * function is responsible for setting this to the length of the
+ * received APDU. This should be ZERO on all errors. The resource
+ * manager will take responsibility of zeroing out any temporary APDU
+ * buffers for security reasons.
+ *
+ * RecvPci Protocol - 0, 1, .... 14 Length - Not used.
+ *
+ * Notes: The driver is responsible for knowing what type of card it
+ * has. If the current slot/card contains a memory card then this
+ * command should ignore the Protocol and use the MCT style commands
+ * for support for these style cards and transmit them appropriately.
+ * If your reader does not support memory cards or you don't want to
+ * then ignore this.
+ *
+ * RxLength should be set to zero on error.
+ *
+ * returns:
+ *
+ * IFD_SUCCESS IFD_COMMUNICATION_ERROR IFD_RESPONSE_TIMEOUT
+ * IFD_ICC_NOT_PRESENT IFD_PROTOCOL_NOT_SUPPORTED
+ */
+
+ RESPONSECODE return_value;
+ unsigned int rx_length;
+ int reader_index;
+
+ (void)RecvPci;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_INFO3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName,
+ Lun);
+
+#ifndef UEFI_DRIVER
+ /* special APDU for the Kobil IDToken (CLASS = 0xFF) */
+ if (KOBIL_IDTOKEN == get_ccid_descriptor(reader_index) -> readerID)
+ {
+ char manufacturer[] = {0xFF, 0x9A, 0x01, 0x01, 0x00};
+ char product_name[] = {0xFF, 0x9A, 0x01, 0x03, 0x00};
+ char firmware_version[] = {0xFF, 0x9A, 0x01, 0x06, 0x00};
+ char driver_version[] = {0xFF, 0x9A, 0x01, 0x07, 0x00};
+
+ if ((sizeof manufacturer == TxLength)
+ && (memcmp(TxBuffer, manufacturer, sizeof manufacturer) == 0))
+ {
+ DEBUG_INFO1("IDToken: Manufacturer command");
+ memcpy(RxBuffer, "KOBIL systems\220\0", 15);
+ *RxLength = 15;
+ return IFD_SUCCESS;
+ }
+
+ if ((sizeof product_name == TxLength)
+ && (memcmp(TxBuffer, product_name, sizeof product_name) == 0))
+ {
+ DEBUG_INFO1("IDToken: Product name command");
+ memcpy(RxBuffer, "IDToken\220\0", 9);
+ *RxLength = 9;
+ return IFD_SUCCESS;
+ }
+
+ if ((sizeof firmware_version == TxLength)
+ && (memcmp(TxBuffer, firmware_version, sizeof firmware_version) == 0))
+ {
+ int IFD_bcdDevice = get_ccid_descriptor(reader_index)->IFD_bcdDevice;
+
+ DEBUG_INFO1("IDToken: Firmware version command");
+ *RxLength = sprintf((char *)RxBuffer, "%X.%02X",
+ IFD_bcdDevice >> 8, IFD_bcdDevice & 0xFF);
+ RxBuffer[(*RxLength)++] = 0x90;
+ RxBuffer[(*RxLength)++] = 0x00;
+ return IFD_SUCCESS;
+ }
+
+ if ((sizeof driver_version == TxLength)
+ && (memcmp(TxBuffer, driver_version, sizeof driver_version) == 0))
+ {
+ DEBUG_INFO1("IDToken: Driver version command");
+#define DRIVER_VERSION "2012.2.7\220\0"
+ memcpy(RxBuffer, DRIVER_VERSION, sizeof DRIVER_VERSION -1);
+ *RxLength = sizeof DRIVER_VERSION -1;
+ return IFD_SUCCESS;
+ }
+
+ }
+#endif
+
+ rx_length = *RxLength;
+ return_value = CmdXfrBlock(reader_index, TxLength, TxBuffer, &rx_length,
+ RxBuffer, SendPci.Protocol);
+ if (IFD_SUCCESS == return_value)
+ *RxLength = rx_length;
+ else
+ *RxLength = 0;
+
+ return return_value;
+} /* IFDHTransmitToICC */
+
+
+EXTERNAL RESPONSECODE IFDHControl(DWORD Lun, DWORD dwControlCode,
+ PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength,
+ PDWORD pdwBytesReturned)
+{
+ /*
+ * This function performs a data exchange with the reader (not the
+ * card) specified by Lun. Here XXXX will only be used. It is
+ * responsible for abstracting functionality such as PIN pads,
+ * biometrics, LCD panels, etc. You should follow the MCT, CTBCS
+ * specifications for a list of accepted commands to implement.
+ *
+ * TxBuffer - Transmit data TxLength - Length of this buffer. RxBuffer
+ * - Receive data RxLength - Length of the received data. This
+ * function will be passed the length of the buffer RxBuffer and it
+ * must set this to the length of the received data.
+ *
+ * Notes: RxLength should be zero on error.
+ */
+ RESPONSECODE return_value = IFD_ERROR_NOT_SUPPORTED;
+ int reader_index;
+ _ccid_descriptor *ccid_descriptor;
+
+ reader_index = LunToReaderIndex(Lun);
+ if ((-1 == reader_index) || (NULL == pdwBytesReturned))
+ return IFD_COMMUNICATION_ERROR;
+
+ ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ DEBUG_INFO4("ControlCode: 0x" DWORD_X ", %s (lun: " DWORD_X ")",
+ dwControlCode, CcidSlots[reader_index].readerName, Lun);
+ DEBUG_INFO_XXD("Control TxBuffer: ", TxBuffer, TxLength);
+
+ /* Set the return length to 0 to avoid problems */
+ *pdwBytesReturned = 0;
+
+ if (IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE == dwControlCode)
+ {
+ int allowed = (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED);
+ int readerID = ccid_descriptor -> readerID;
+
+ if (VENDOR_GEMALTO == GET_VENDOR(readerID))
+ {
+ unsigned char switch_interface[] = { 0x52, 0xF8, 0x04, 0x01, 0x00 };
+
+ /* get firmware version escape command */
+ if ((1 == TxLength) && (0x02 == TxBuffer[0]))
+ allowed = TRUE;
+
+ /* switch interface escape command on the GemProx DU
+ * the next byte in the command is the interface:
+ * 0x01 switch to contactless interface
+ * 0x02 switch to contact interface
+ */
+ if ((GEMALTOPROXDU == readerID)
+ && (6 == TxLength)
+ && (0 == memcmp(TxBuffer, switch_interface, sizeof(switch_interface))))
+ allowed = TRUE;
+ }
+
+ if (!allowed)
+ {
+ DEBUG_INFO1("ifd exchange (Escape command) not allowed");
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+ else
+ {
+ unsigned int iBytesReturned;
+
+ iBytesReturned = RxLength;
+ /* 30 seconds timeout for long commands */
+ return_value = CmdEscape(reader_index, TxBuffer, TxLength,
+ RxBuffer, &iBytesReturned, 30*1000);
+ *pdwBytesReturned = iBytesReturned;
+ }
+ }
+
+ /* Implement the PC/SC v2.02.07 Part 10 IOCTL mechanism */
+
+ /* Query for features */
+ /* 0x313520 is the Windows value for SCARD_CTL_CODE(3400)
+ * This hack is needed for RDP applications */
+ if ((CM_IOCTL_GET_FEATURE_REQUEST == dwControlCode)
+ || (0x313520 == dwControlCode))
+ {
+ unsigned int iBytesReturned = 0;
+ PCSC_TLV_STRUCTURE *pcsc_tlv = (PCSC_TLV_STRUCTURE *)RxBuffer;
+ int readerID = ccid_descriptor -> readerID;
+
+ /* we need room for up to five records */
+ if (RxLength < 6 * sizeof(PCSC_TLV_STRUCTURE))
+ return IFD_ERROR_INSUFFICIENT_BUFFER;
+
+ /* We can only support direct verify and/or modify currently */
+ if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_VERIFY)
+ {
+ pcsc_tlv -> tag = FEATURE_VERIFY_PIN_DIRECT;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_FEATURE_VERIFY_PIN_DIRECT);
+
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+ }
+
+ if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_MODIFY)
+ {
+ pcsc_tlv -> tag = FEATURE_MODIFY_PIN_DIRECT;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_FEATURE_MODIFY_PIN_DIRECT);
+
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+ }
+
+ /* Provide IFD_PIN_PROPERTIES only for pinpad readers */
+ if (ccid_descriptor -> bPINSupport)
+ {
+ pcsc_tlv -> tag = FEATURE_IFD_PIN_PROPERTIES;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_FEATURE_IFD_PIN_PROPERTIES);
+
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+ }
+
+ if ((KOBIL_TRIBANK == readerID)
+ || (KOBIL_MIDENTITY_VISUAL == readerID))
+ {
+ pcsc_tlv -> tag = FEATURE_MCT_READER_DIRECT;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_FEATURE_MCT_READER_DIRECT);
+
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+ }
+
+ pcsc_tlv -> tag = FEATURE_GET_TLV_PROPERTIES;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_FEATURE_GET_TLV_PROPERTIES);
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+
+ /* IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE */
+ if (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED)
+ {
+ pcsc_tlv -> tag = FEATURE_CCID_ESC_COMMAND;
+ pcsc_tlv -> length = 0x04; /* always 0x04 */
+ pcsc_tlv -> value = htonl(IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE);
+
+ pcsc_tlv++;
+ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
+ }
+
+ *pdwBytesReturned = iBytesReturned;
+ return_value = IFD_SUCCESS;
+ }
+
+ /* Get PIN handling capabilities */
+ if (IOCTL_FEATURE_IFD_PIN_PROPERTIES == dwControlCode)
+ {
+ PIN_PROPERTIES_STRUCTURE *caps = (PIN_PROPERTIES_STRUCTURE *)RxBuffer;
+ int validation;
+
+ if (RxLength < sizeof(PIN_PROPERTIES_STRUCTURE))
+ return IFD_ERROR_INSUFFICIENT_BUFFER;
+
+ /* Only give the LCD size for now */
+ caps -> wLcdLayout = ccid_descriptor -> wLcdLayout;
+
+ /* Hardcoded special reader cases */
+ switch (ccid_descriptor->readerID)
+ {
+ case GEMPCPINPAD:
+ case VEGAALPHA:
+ case CHERRYST2000:
+ validation = 0x02; /* Validation key pressed */
+ break;
+ default:
+ validation = 0x07; /* Default */
+ }
+
+ /* Gemalto readers providing firmware features */
+ if (ccid_descriptor -> gemalto_firmware_features)
+ validation = ccid_descriptor -> gemalto_firmware_features -> bEntryValidationCondition;
+
+ caps -> bEntryValidationCondition = validation;
+ caps -> bTimeOut2 = 0x00; /* We do not distinguish bTimeOut from TimeOut2 */
+
+ *pdwBytesReturned = sizeof(*caps);
+ return_value = IFD_SUCCESS;
+ }
+
+ /* Reader features */
+ if (IOCTL_FEATURE_GET_TLV_PROPERTIES == dwControlCode)
+ {
+ int p = 0;
+ int tmp;
+
+ /* wLcdLayout */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdLayout; /* tag */
+ RxBuffer[p++] = 2; /* length */
+ tmp = ccid_descriptor -> wLcdLayout;
+ RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */
+ RxBuffer[p++] = (tmp >> 8) & 0xFF;
+
+ /* only if the reader has a display */
+ if (ccid_descriptor -> wLcdLayout)
+ {
+ /* wLcdMaxCharacters */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdMaxCharacters; /* tag */
+ RxBuffer[p++] = 2; /* length */
+ tmp = ccid_descriptor -> wLcdLayout & 0xFF;
+ RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */
+ RxBuffer[p++] = (tmp >> 8) & 0xFF;
+
+ /* wLcdMaxLines */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdMaxLines; /* tag */
+ RxBuffer[p++] = 2; /* length */
+ tmp = ccid_descriptor -> wLcdLayout >> 8;
+ RxBuffer[p++] = tmp & 0xFF; /* value in little endian order */
+ RxBuffer[p++] = (tmp >> 8) & 0xFF;
+ }
+
+ /* bTimeOut2 */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bTimeOut2;
+ RxBuffer[p++] = 1; /* length */
+ /* IFD does not distinguish bTimeOut from bTimeOut2 */
+ RxBuffer[p++] = 0x00;
+
+ /* sFirmwareID */
+ if (VENDOR_GEMALTO == GET_VENDOR(ccid_descriptor -> readerID))
+ {
+ unsigned char firmware[256];
+ const unsigned char cmd[] = { 0x02 };
+ RESPONSECODE ret;
+ unsigned int len;
+
+ len = sizeof(firmware);
+ ret = CmdEscape(reader_index, cmd, sizeof(cmd), firmware, &len, 0);
+
+ if (IFD_SUCCESS == ret)
+ {
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_sFirmwareID;
+ RxBuffer[p++] = len;
+ memcpy(&RxBuffer[p], firmware, len);
+ p += len;
+ }
+ }
+
+ /* Gemalto PC Pinpad V1 */
+ if (((GEMPCPINPAD == ccid_descriptor -> readerID)
+ && (0x0100 == ccid_descriptor -> IFD_bcdDevice))
+ /* Covadis Véga-Alpha */
+ || (VEGAALPHA == ccid_descriptor->readerID))
+ {
+ /* bMinPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 4; /* min PIN size */
+
+ /* bMaxPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 8; /* max PIN size */
+
+ /* bEntryValidationCondition */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 0x02; /* validation key pressed */
+ }
+
+ /* Cherry GmbH SmartTerminal ST-2xxx */
+ if (CHERRYST2000 == ccid_descriptor -> readerID)
+ {
+ /* bMinPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 0; /* min PIN size */
+
+ /* bMaxPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 25; /* max PIN size */
+
+ /* bEntryValidationCondition */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = 0x02; /* validation key pressed */
+ }
+
+ /* Gemalto readers providing firmware features */
+ if (ccid_descriptor -> gemalto_firmware_features)
+ {
+ struct GEMALTO_FIRMWARE_FEATURES *features = ccid_descriptor -> gemalto_firmware_features;
+
+ /* bMinPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = features -> MinimumPINSize; /* min PIN size */
+
+ /* bMaxPINSize */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = features -> MaximumPINSize; /* max PIN size */
+
+ /* bEntryValidationCondition */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] = features -> bEntryValidationCondition; /* validation key pressed */
+ }
+
+ /* bPPDUSupport */
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bPPDUSupport;
+ RxBuffer[p++] = 1; /* length */
+ RxBuffer[p++] =
+ (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED) ? 1 : 0;
+ /* bit0: PPDU is supported over SCardControl using
+ * FEATURE_CCID_ESC_COMMAND */
+
+ /* wIdVendor */
+ {
+ int idVendor = ccid_descriptor -> readerID >> 16;
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wIdVendor;
+ RxBuffer[p++] = 2; /* length */
+ RxBuffer[p++] = idVendor & 0xFF;
+ RxBuffer[p++] = idVendor >> 8;
+ }
+
+ /* wIdProduct */
+ {
+ int idProduct = ccid_descriptor -> readerID & 0xFFFF;
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wIdProduct;
+ RxBuffer[p++] = 2; /* length */
+ RxBuffer[p++] = idProduct & 0xFF;
+ RxBuffer[p++] = idProduct >> 8;
+ }
+
+ /* dwMaxAPDUDataSize */
+ {
+ int MaxAPDUDataSize = 0; /* short APDU only by default */
+
+ /* reader is TPDU or extended APDU */
+ if ((ccid_descriptor -> dwFeatures & CCID_CLASS_EXTENDED_APDU)
+ || (ccid_descriptor -> dwFeatures & CCID_CLASS_TPDU))
+ MaxAPDUDataSize = 0x10000;
+
+ RxBuffer[p++] = PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize;
+ RxBuffer[p++] = 4; /* length */
+ RxBuffer[p++] = MaxAPDUDataSize & 0xFF;
+ RxBuffer[p++] = (MaxAPDUDataSize >> 8) & 0xFF;
+ RxBuffer[p++] = (MaxAPDUDataSize >> 16) & 0xFF;
+ RxBuffer[p++] = (MaxAPDUDataSize >> 24) & 0xFF;
+ }
+
+ *pdwBytesReturned = p;
+ return_value = IFD_SUCCESS;
+ }
+
+ /* Verify a PIN, plain CCID */
+ if (IOCTL_FEATURE_VERIFY_PIN_DIRECT == dwControlCode)
+ {
+ unsigned int iBytesReturned;
+
+ iBytesReturned = RxLength;
+ return_value = SecurePINVerify(reader_index, TxBuffer, TxLength,
+ RxBuffer, &iBytesReturned);
+ *pdwBytesReturned = iBytesReturned;
+ }
+
+ /* Modify a PIN, plain CCID */
+ if (IOCTL_FEATURE_MODIFY_PIN_DIRECT == dwControlCode)
+ {
+ unsigned int iBytesReturned;
+
+ iBytesReturned = RxLength;
+ return_value = SecurePINModify(reader_index, TxBuffer, TxLength,
+ RxBuffer, &iBytesReturned);
+ *pdwBytesReturned = iBytesReturned;
+ }
+
+ /* MCT: Multifunctional Card Terminal */
+ if (IOCTL_FEATURE_MCT_READER_DIRECT == dwControlCode)
+ {
+ if ( (TxBuffer[0] != 0x20) /* CLA */
+ || ((TxBuffer[1] & 0xF0) != 0x70) /* INS */
+ /* valid INS are
+ * 0x70: SECODER INFO
+ * 0x71: SECODER SELECT APPLICATION
+ * 0x72: SECODER APPLICATION ACTIVE
+ * 0x73: SECODER DATA CONFIRMATION
+ * 0x74: SECODER PROCESS AUTHENTICATION TOKEN */
+ || ((TxBuffer[1] & 0x0F) > 4)
+ || (TxBuffer[2] != 0x00) /* P1 */
+ || (TxBuffer[3] != 0x00) /* P2 */
+ || (TxBuffer[4] != 0x00) /* Lind */
+ )
+ {
+ DEBUG_INFO1("MCT Command refused by driver");
+ return_value = IFD_COMMUNICATION_ERROR;
+ }
+ else
+ {
+ unsigned int iBytesReturned;
+
+ /* we just transmit the buffer as a CCID Escape command */
+ iBytesReturned = RxLength;
+ return_value = CmdEscape(reader_index, TxBuffer, TxLength,
+ RxBuffer, &iBytesReturned, 0);
+ *pdwBytesReturned = iBytesReturned;
+ }
+ }
+
+ if (IFD_SUCCESS != return_value)
+ *pdwBytesReturned = 0;
+
+ DEBUG_INFO_XXD("Control RxBuffer: ", RxBuffer, *pdwBytesReturned);
+ return return_value;
+} /* IFDHControl */
+
+
+EXTERNAL RESPONSECODE IFDHICCPresence(DWORD Lun)
+{
+ /*
+ * This function returns the status of the card inserted in the
+ * reader/slot specified by Lun. It will return either:
+ *
+ * returns: IFD_ICC_PRESENT IFD_ICC_NOT_PRESENT
+ * IFD_COMMUNICATION_ERROR
+ */
+
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+ RESPONSECODE return_value = IFD_COMMUNICATION_ERROR;
+ int oldLogLevel;
+ int reader_index;
+ _ccid_descriptor *ccid_descriptor;
+ unsigned int oldReadTimeout;
+
+ if (-1 == (reader_index = LunToReaderIndex(Lun)))
+ return IFD_COMMUNICATION_ERROR;
+
+ DEBUG_PERIODIC3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName, Lun);
+
+ ccid_descriptor = get_ccid_descriptor(reader_index);
+
+ if ((GEMCORESIMPRO == ccid_descriptor->readerID)
+ && (ccid_descriptor->IFD_bcdDevice < 0x0200))
+ {
+ /* GemCore SIM Pro firmware 2.00 and up features
+ * a full independant second slot */
+ return_value = ccid_descriptor->dwSlotStatus;
+ goto end;
+ }
+
+ /* save the current read timeout computed from card capabilities */
+ oldReadTimeout = ccid_descriptor->readTimeout;
+
+ /* use default timeout since the reader may not be present anymore */
+ ccid_descriptor->readTimeout = DEFAULT_COM_READ_TIMEOUT;
+
+ /* if DEBUG_LEVEL_PERIODIC is not set we remove DEBUG_LEVEL_COMM */
+ oldLogLevel = LogLevel;
+ if (! (LogLevel & DEBUG_LEVEL_PERIODIC))
+ LogLevel &= ~DEBUG_LEVEL_COMM;
+
+ return_value = CmdGetSlotStatus(reader_index, pcbuffer);
+
+ /* set back the old timeout */
+ ccid_descriptor->readTimeout = oldReadTimeout;
+
+ /* set back the old LogLevel */
+ LogLevel = oldLogLevel;
+
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ return_value = IFD_COMMUNICATION_ERROR;
+ switch (pcbuffer[7] & CCID_ICC_STATUS_MASK) /* bStatus */
+ {
+ case CCID_ICC_PRESENT_ACTIVE:
+ return_value = IFD_ICC_PRESENT;
+ /* use default slot */
+ break;
+
+ case CCID_ICC_PRESENT_INACTIVE:
+ if ((CcidSlots[reader_index].bPowerFlags == POWERFLAGS_RAZ)
+ || (CcidSlots[reader_index].bPowerFlags & MASK_POWERFLAGS_PDWN))
+ /* the card was previously absent */
+ return_value = IFD_ICC_PRESENT;
+ else
+ {
+ /* the card was previously present but has been
+ * removed and inserted between two consecutive
+ * IFDHICCPresence() calls */
+ CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
+ return_value = IFD_ICC_NOT_PRESENT;
+ }
+ break;
+
+ case CCID_ICC_ABSENT:
+ /* Reset ATR buffer */
+ CcidSlots[reader_index].nATRLength = 0;
+ *CcidSlots[reader_index].pcATRBuffer = '\0';
+
+ /* Reset PowerFlags */
+ CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
+
+ return_value = IFD_ICC_NOT_PRESENT;
+ break;
+ }
+
+#if 0
+ /* SCR331-DI contactless reader */
+ if (((SCR331DI == ccid_descriptor->readerID)
+ || (SDI010 == ccid_descriptor->readerID)
+ || (SCR331DINTTCOM == ccid_descriptor->readerID))
+ && (ccid_descriptor->bCurrentSlotIndex > 0))
+ {
+ unsigned char cmd[] = { 0x11 };
+ /* command: 11 ??
+ * response: 00 11 01 ?? no card
+ * 01 04 00 ?? card present */
+
+ unsigned char res[10];
+ unsigned int length_res = sizeof(res);
+ RESPONSECODE ret;
+
+ /* if DEBUG_LEVEL_PERIODIC is not set we remove DEBUG_LEVEL_COMM */
+ oldLogLevel = LogLevel;
+ if (! (LogLevel & DEBUG_LEVEL_PERIODIC))
+ LogLevel &= ~DEBUG_LEVEL_COMM;
+
+ ret = CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, 0);
+
+ /* set back the old LogLevel */
+ LogLevel = oldLogLevel;
+
+ if (ret != IFD_SUCCESS)
+ {
+ DEBUG_INFO1("CmdEscape failed");
+ /* simulate a card absent */
+ res[0] = 0;
+ }
+
+ if (0x01 == res[0])
+ return_value = IFD_ICC_PRESENT;
+ else
+ {
+ /* Reset ATR buffer */
+ CcidSlots[reader_index].nATRLength = 0;
+ *CcidSlots[reader_index].pcATRBuffer = '\0';
+
+ /* Reset PowerFlags */
+ CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
+
+ return_value = IFD_ICC_NOT_PRESENT;
+ }
+ }
+#endif
+
+end:
+ DEBUG_PERIODIC2("Card %s",
+ IFD_ICC_PRESENT == return_value ? "present" : "absent");
+
+ return return_value;
+} /* IFDHICCPresence */
+
+
+CcidDesc *get_ccid_slot(unsigned int reader_index)
+{
+ return &CcidSlots[reader_index];
+} /* get_ccid_slot */
+
+
+void init_driver(void)
+{
+#ifndef UEFI_DRIVER
+ char infofile[FILENAME_MAX];
+ char *e;
+ int rv;
+ list_t plist, *values;
+
+ DEBUG_INFO1("Driver version: " VERSION);
+
+ /* Info.plist full patch filename */
+ (void)snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist",
+ PCSCLITE_HP_DROPDIR, BUNDLE);
+
+ rv = bundleParse(infofile, &plist);
+ if (0 == rv)
+ {
+ /* Log level */
+ rv = LTPBundleFindValueWithKey(&plist, "ifdLogLevel", &values);
+ if (0 == rv)
+ {
+ /* convert from hex or dec or octal */
+ LogLevel = strtoul(list_get_at(values, 0), NULL, 0);
+
+ /* print the log level used */
+ DEBUG_INFO2("LogLevel: 0x%.4X", LogLevel);
+ }
+
+ /* Driver options */
+ rv = LTPBundleFindValueWithKey(&plist, "ifdDriverOptions", &values);
+ if (0 == rv)
+ {
+ /* convert from hex or dec or octal */
+ DriverOptions = strtoul(list_get_at(values, 0), NULL, 0);
+
+ /* print the log level used */
+ DEBUG_INFO2("DriverOptions: 0x%.4X", DriverOptions);
+ }
+
+ bundleRelease(&plist);
+ }
+
+ e = getenv("LIBCCID_ifdLogLevel");
+ if (e)
+ {
+ /* convert from hex or dec or octal */
+ LogLevel = strtoul(e, NULL, 0);
+
+ /* print the log level used */
+ DEBUG_INFO2("LogLevel from LIBCCID_ifdLogLevel: 0x%.4X", LogLevel);
+ }
+
+ /* get the voltage parameter */
+ switch ((DriverOptions >> 4) & 0x03)
+ {
+ case 0:
+ PowerOnVoltage = VOLTAGE_5V;
+ break;
+
+ case 1:
+ PowerOnVoltage = VOLTAGE_3V;
+ break;
+
+ case 2:
+ PowerOnVoltage = VOLTAGE_1_8V;
+ break;
+
+ case 3:
+ PowerOnVoltage = VOLTAGE_AUTO;
+ break;
+ }
+#else
+ /* full debug */
+ LogLevel = DEBUG_LEVEL_CRITICAL | DEBUG_LEVEL_INFO | DEBUG_LEVEL_PERIODIC | DEBUG_LEVEL_COMM;
+#endif
+
+ /* initialise the Lun to reader_index mapping */
+ InitReaderIndex();
+
+ DebugInitialized = TRUE;
+} /* init_driver */
+
+
+void extra_egt(ATR_t *atr, _ccid_descriptor *ccid_desc, DWORD Protocol)
+{
+ /* This function use an EGT value for cards who comply with followings
+ * criterias:
+ * - TA1 > 11
+ * - current EGT = 0x00 or 0xFF
+ * - T=0 or (T=1 and CWI >= 2)
+ *
+ * Without this larger EGT some non ISO 7816-3 smart cards may not
+ * communicate with the reader.
+ *
+ * This modification is harmless, the reader will just be less restrictive
+ */
+
+ unsigned int card_baudrate;
+ unsigned int default_baudrate;
+ double f, d;
+
+ /* if TA1 not present */
+ if (! atr->ib[0][ATR_INTERFACE_BYTE_TA].present)
+ return;
+
+ (void)ATR_GetParameter(atr, ATR_PARAMETER_D, &d);
+ (void)ATR_GetParameter(atr, ATR_PARAMETER_F, &f);
+
+ /* may happen with non ISO cards */
+ if ((0 == f) || (0 == d))
+ return;
+
+ /* Baudrate = f x D/F */
+ card_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock * d / f);
+
+ default_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock
+ * ATR_DEFAULT_D / ATR_DEFAULT_F);
+
+ /* TA1 > 11? */
+ if (card_baudrate <= default_baudrate)
+ return;
+
+ /* Current EGT = 0 or FF? */
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TC].present &&
+ ((0x00 == atr->ib[0][ATR_INTERFACE_BYTE_TC].value) ||
+ (0xFF == atr->ib[0][ATR_INTERFACE_BYTE_TC].value)))
+ {
+ if (SCARD_PROTOCOL_T0 == Protocol)
+ {
+ /* Init TC1 */
+ atr->ib[0][ATR_INTERFACE_BYTE_TC].present = TRUE;
+ atr->ib[0][ATR_INTERFACE_BYTE_TC].value = 2;
+ DEBUG_INFO1("Extra EGT patch applied");
+ }
+
+ if (SCARD_PROTOCOL_T1 == Protocol)
+ {
+ int i;
+
+ /* TBi (i>2) present? BWI/CWI */
+ for (i=2; i<ATR_MAX_PROTOCOLS; i++)
+ {
+ /* CWI >= 2 ? */
+ if (atr->ib[i][ATR_INTERFACE_BYTE_TB].present &&
+ ((atr->ib[i][ATR_INTERFACE_BYTE_TB].value & 0x0F) >= 2))
+ {
+ /* Init TC1 */
+ atr->ib[0][ATR_INTERFACE_BYTE_TC].present = TRUE;
+ atr->ib[0][ATR_INTERFACE_BYTE_TC].value = 2;
+ DEBUG_INFO1("Extra EGT patch applied");
+
+ /* only the first TBi (i>2) must be used */
+ break;
+ }
+ }
+ }
+ }
+} /* extra_egt */
+
+
+static char find_baud_rate(unsigned int baudrate, unsigned int *list)
+{
+ int i;
+
+ DEBUG_COMM2("Card baud rate: %d", baudrate);
+
+ /* Does the reader support the announced smart card data speed? */
+ for (i=0;; i++)
+ {
+ /* end of array marker */
+ if (0 == list[i])
+ break;
+
+ DEBUG_COMM2("Reader can do: %d", list[i]);
+
+ /* We must take into account that the card_baudrate integral value
+ * is an approximative result, computed from the d/f float result.
+ */
+ if ((baudrate < list[i] + 2) && (baudrate > list[i] - 2))
+ return TRUE;
+ }
+
+ return FALSE;
+} /* find_baud_rate */
+
+
+static unsigned int T0_card_timeout(double f, double d, int TC1, int TC2,
+ int clock_frequency)
+{
+ unsigned int timeout = DEFAULT_COM_READ_TIMEOUT;
+ double EGT, WWT;
+ unsigned int t;
+
+ /* Timeout applied on ISO_IN or ISO_OUT card exchange
+ * we choose the maximum computed value.
+ *
+ * ISO_IN timeout is the sum of:
+ * Terminal: Smart card:
+ * 5 bytes header cmd ->
+ * <- Procedure byte
+ * 256 data bytes ->
+ * <- SW1-SW2
+ * = 261 EGT + 3 WWT + 3 WWT
+ *
+ * ISO_OUT Timeout is the sum of:
+ * Terminal: Smart card:
+ * 5 bytes header cmd ->
+ * <- Procedure byte + 256 data bytes + SW1-SW2
+ * = 5 EGT + 1 WWT + 259 WWT
+ */
+
+ /* clock_frequency is in kHz so the times are in milliseconds and not
+ * in seconds */
+
+ /* may happen with non ISO cards */
+ if ((0 == f) || (0 == d) || (0 == clock_frequency))
+ return 60 * 1000; /* 60 seconds */
+
+ /* EGT */
+ /* see ch. 6.5.3 Extra Guard Time, page 12 of ISO 7816-3 */
+ EGT = 12 * f / d / clock_frequency + (f / d) * TC1 / clock_frequency;
+
+ /* card WWT */
+ /* see ch. 8.2 Character level, page 15 of ISO 7816-3 */
+ WWT = 960 * TC2 * f / clock_frequency;
+
+ /* ISO in */
+ t = 261 * EGT + (3 + 3) * WWT;
+ if (timeout < t)
+ timeout = t;
+
+ /* ISO out */
+ t = 5 * EGT + (1 + 259) * WWT;
+ if (timeout < t)
+ timeout = t;
+
+ return timeout;
+} /* T0_card_timeout */
+
+
+static unsigned int T1_card_timeout(double f, double d, int TC1,
+ int BWI, int CWI, int clock_frequency)
+{
+ double EGT, BWT, CWT, etu;
+ unsigned int timeout;
+
+ /* Timeout applied on ISO in + ISO out card exchange
+ *
+ * Timeout is the sum of:
+ * - ISO in delay between leading edge of the first character sent by the
+ * interface device and the last one (NAD PCB LN APDU CKS) = 260 EGT,
+ * - delay between ISO in and ISO out = BWT,
+ * - ISO out delay between leading edge of the first character sent by the
+ * card and the last one (NAD PCB LN DATAS CKS) = 260 CWT.
+ */
+
+ /* clock_frequency is in kHz so the times are in milliseconds and not
+ * in seconds */
+
+ /* may happen with non ISO cards */
+ if ((0 == f) || (0 == d) || (0 == clock_frequency))
+ return 60 * 1000; /* 60 seconds */
+
+ /* see ch. 6.5.2 Transmission factors F and D, page 12 of ISO 7816-3 */
+ etu = f / d / clock_frequency;
+
+ /* EGT */
+ /* see ch. 6.5.3 Extra Guard Time, page 12 of ISO 7816-3 */
+ EGT = 12 * etu + (f / d) * TC1 / clock_frequency;
+
+ /* card BWT */
+ /* see ch. 9.5.3.2 Block Waiting Time, page 20 of ISO 7816-3 */
+ BWT = 11 * etu + (1<<BWI) * 960 * 372 / clock_frequency;
+
+ /* card CWT */
+ /* see ch. 9.5.3.1 Caracter Waiting Time, page 20 of ISO 7816-3 */
+ CWT = (11 + (1<<CWI)) * etu;
+
+ timeout = 260*EGT + BWT + 260*CWT;
+
+ /* This is the card/reader timeout. Add 1 second for the libusb
+ * timeout so we get the error from the reader. */
+ timeout += 1000;
+
+ return timeout;
+} /* T1_card_timeout */
+
+
+static int get_IFSC(ATR_t *atr, int *idx)
+{
+ int i, ifsc, protocol = -1;
+
+ /* default return values */
+ ifsc = -1;
+ *idx = -1;
+
+ for (i=0; i<ATR_MAX_PROTOCOLS; i++)
+ {
+ /* TAi (i>2) present and protocol=1 => IFSC */
+ if (i >= 2 && protocol == 1
+ && atr->ib[i][ATR_INTERFACE_BYTE_TA].present)
+ {
+ ifsc = atr->ib[i][ATR_INTERFACE_BYTE_TA].value;
+ *idx = i+1;
+ /* only the first TAi (i>2) must be used */
+ break;
+ }
+
+ /* protocol T=? */
+ if (atr->ib[i][ATR_INTERFACE_BYTE_TD].present)
+ protocol = atr->ib[i][ATR_INTERFACE_BYTE_TD].value & 0x0F;
+ }
+
+ if (ifsc > 254)
+ {
+ /* 0xFF is not a valid value for IFSC */
+ DEBUG_INFO2("Non ISO IFSC: 0x%X", ifsc);
+ ifsc = 254;
+ }
+
+ return ifsc;
+} /* get_IFSC */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE b/MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE
new file mode 100644
index 0000000..2b5c118
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE
@@ -0,0 +1,28 @@
+OpenCT, a middleware framework for smart card terminals.
+
+Copyright (c) 2003, Olaf Kirch <***@suse.de>
+Copyright (c) 2003, Andreas Jellinghaus <***@dungeon.inka.de>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the authors nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/README b/MdeModulePkg/Library/SmartCardReader/libccid/openct/README
new file mode 100644
index 0000000..77d79b0
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/README
@@ -0,0 +1,7 @@
+The files buffer.[c|h], checksum.c and proto-t1.c comes from the OpenCT
+project <http://www.opensc.org/>
+
+I (Ludovic Rousseau) greatly patched proto-t1.c to add all the needed
+code to reach the quality level requested by the EMV standard.
+
+$Id: README 1021 2004-07-02 12:06:44Z rousseau $
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c b/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c
new file mode 100644
index 0000000..db98684
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c
@@ -0,0 +1,73 @@
+/*
+ * Buffer handling functions
+ *
+ * Copyright (C) 2003, Olaf Kirch <***@suse.de>
+ */
+
+#include <config.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <openct/buffer.h>
+
+void
+ct_buf_init(ct_buf_t *bp, void *mem, size_t len)
+{
+ memset(bp, 0, sizeof(*bp));
+ bp->base = (unsigned char *) mem;
+ bp->size = len;
+}
+
+void
+ct_buf_set(ct_buf_t *bp, void *mem, size_t len)
+{
+ ct_buf_init(bp, mem, len);
+ bp->tail = len;
+}
+
+int
+ct_buf_get(ct_buf_t *bp, void *mem, size_t len)
+{
+ if (len > bp->tail - bp->head)
+ return -1;
+ if (mem)
+ memcpy(mem, bp->base + bp->head, len);
+ bp->head += len;
+ return len;
+}
+
+int
+ct_buf_put(ct_buf_t *bp, const void *mem, size_t len)
+{
+ if (len > bp->size - bp->tail) {
+ bp->overrun = 1;
+ return -1;
+ }
+ if (mem)
+ memcpy(bp->base + bp->tail, mem, len);
+ bp->tail += len;
+ return len;
+}
+
+int
+ct_buf_putc(ct_buf_t *bp, int byte)
+{
+ unsigned char c = byte;
+
+ return ct_buf_put(bp, &c, 1);
+}
+
+unsigned int
+ct_buf_avail(ct_buf_t *bp)
+{
+ return bp->tail - bp->head;
+}
+
+void *
+ct_buf_head(ct_buf_t *bp)
+{
+ return bp->base + bp->head;
+}
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h b/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h
new file mode 100644
index 0000000..c05e470
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h
@@ -0,0 +1,36 @@
+/*
+ * Buffer handling functions of the IFD handler library
+ *
+ * Copyright (C) 2003, Olaf Kirch <***@suse.de>
+ */
+
+#ifndef OPENCT_BUFFER_H
+#define OPENCT_BUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+typedef struct ct_buf {
+ unsigned char * base;
+ unsigned int head, tail, size;
+ unsigned int overrun;
+} ct_buf_t;
+
+extern void ct_buf_init(ct_buf_t *, void *, size_t);
+extern void ct_buf_set(ct_buf_t *, void *, size_t);
+extern int ct_buf_get(ct_buf_t *, void *, size_t);
+extern int ct_buf_put(ct_buf_t *, const void *, size_t);
+extern int ct_buf_putc(ct_buf_t *, int);
+extern unsigned int ct_buf_avail(ct_buf_t *);
+extern void * ct_buf_head(ct_buf_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPENCT_BUFFER_H */
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c b/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c
new file mode 100644
index 0000000..744d910
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c
@@ -0,0 +1,95 @@
+/*
+ * Checksum handling
+ *
+ * Copyright Matthias Bruestle 1999-2002
+ * For licensing, see the file LICENCE
+ */
+
+#include <config.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include "checksum.h"
+
+#define min( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
+
+/* ISO STD 3309 */
+/* From: ***@catbyte.b30.ingr.com (Dave Medin)
+ * Subject: CCITT checksums
+ * Newsgroups: sci.electronics
+ * Date: Mon, 7 Dec 1992 17:33:39 GMT
+ */
+
+/* Correct Table? */
+
+static unsigned short crctab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/*
+ * Returns LRC of data.
+ */
+unsigned int
+csum_lrc_compute(const uint8_t *in, size_t len, unsigned char *rc)
+{
+ unsigned char lrc = 0;
+
+ while (len--)
+ lrc ^= *in++;
+
+ if (rc)
+ *rc = lrc;
+ return 1;
+}
+
+/*
+ * Compute CRC of data.
+ */
+unsigned int
+csum_crc_compute(const uint8_t * data, size_t len, unsigned char *rc)
+{
+ unsigned short v = 0xFFFF;
+
+ while (len--) {
+ v = ((v >> 8) & 0xFF) ^ crctab[(v ^ *data++) & 0xFF];
+ }
+
+ if (rc) {
+ rc[0] = (v >> 8) & 0xFF;
+ rc[1] = v & 0xFF;
+ }
+
+ return 2;
+}
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h b/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h
new file mode 100644
index 0000000..68445f0
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h
@@ -0,0 +1,37 @@
+/*
+ proto-t1.h: header file for proto-t1.c
+ Copyright (C) 2004 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/* $Id: checksum.h 6975 2014-09-04 11:33:05Z rousseau $ */
+
+#ifndef __CHECKSUM_H__
+#define __CHECKSUM_H__
+
+#include <config.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+extern unsigned int csum_lrc_compute(const uint8_t *, size_t, unsigned char *);
+extern unsigned int csum_crc_compute(const uint8_t *, size_t, unsigned char *);
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c b/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c
new file mode 100644
index 0000000..912a1b5
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c
@@ -0,0 +1,800 @@
+/*
+ * Implementation of T=1
+ *
+ * Copyright (C) 2003, Olaf Kirch <***@suse.de>
+ *
+ * improvements by:
+ * Copyright (C) 2004 Ludovic Rousseau <***@free.fr>
+ */
+
+#include <config.h>
+
+#include <pcsclite.h>
+#include <ifdhandler.h>
+#include "commands.h"
+#include "buffer.h"
+#include "debug.h"
+#include "proto-t1.h"
+#include "checksum.h"
+
+#include "ccid.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+/* I block */
+#define T1_I_SEQ_SHIFT 6
+
+/* R block */
+#define T1_IS_ERROR(pcb) ((pcb) & 0x0F)
+#define T1_EDC_ERROR 0x01
+#define T1_OTHER_ERROR 0x02
+#define T1_R_SEQ_SHIFT 4
+
+/* S block stuff */
+#define T1_S_IS_RESPONSE(pcb) ((pcb) & T1_S_RESPONSE)
+#define T1_S_TYPE(pcb) ((pcb) & 0x0F)
+#define T1_S_RESPONSE 0x20
+#define T1_S_RESYNC 0x00
+#define T1_S_IFS 0x01
+#define T1_S_ABORT 0x02
+#define T1_S_WTX 0x03
+
+#define swap_nibbles(x) ( (x >> 4) | ((x & 0xF) << 4) )
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define NAD 0
+#define PCB 1
+#define LEN 2
+#define DATA 3
+
+/* internal state, do not mess with it. */
+/* should be != DEAD after reset/init */
+enum {
+ SENDING, RECEIVING, RESYNCH, DEAD
+};
+
+static void t1_set_checksum(t1_state_t *, int);
+static unsigned int t1_block_type(unsigned char);
+static unsigned int t1_seq(unsigned char);
+static unsigned int t1_rebuild(t1_state_t *t1, unsigned char *block);
+static unsigned int t1_compute_checksum(t1_state_t *, unsigned char *, size_t);
+static int t1_verify_checksum(t1_state_t *, unsigned char *, size_t);
+static int t1_xcv(t1_state_t *, unsigned char *, size_t, size_t);
+
+/*
+ * Set default T=1 protocol parameters
+ */
+static void t1_set_defaults(t1_state_t * t1)
+{
+ t1->retries = 3;
+ /* This timeout is rather insane, but we need this right now
+ * to support cryptoflex keygen */
+ t1->ifsc = 32;
+ t1->ifsd = 32;
+ t1->nr = 0;
+ t1->ns = 0;
+ t1->wtx = 0;
+}
+
+static void t1_set_checksum(t1_state_t * t1, int csum)
+{
+ switch (csum) {
+ case IFD_PROTOCOL_T1_CHECKSUM_LRC:
+ t1->rc_bytes = 1;
+ t1->checksum = csum_lrc_compute;
+ break;
+ case IFD_PROTOCOL_T1_CHECKSUM_CRC:
+ t1->rc_bytes = 2;
+ t1->checksum = csum_crc_compute;
+ break;
+ }
+}
+
+/*
+ * Attach t1 protocol
+ */
+int t1_init(t1_state_t * t1, int lun)
+{
+ t1_set_defaults(t1);
+ t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC, 0);
+ t1_set_param(t1, IFD_PROTOCOL_T1_STATE, SENDING);
+ t1_set_param(t1, IFD_PROTOCOL_T1_MORE, FALSE);
+
+ t1->lun = lun;
+
+ return 0;
+}
+
+/*
+ * Detach t1 protocol
+ */
+void t1_release(/*@unused@*/ t1_state_t * t1)
+{
+ (void)t1;
+ /* NOP */
+}
+
+/*
+ * Get/set parmaters for T1 protocol
+ */
+int t1_set_param(t1_state_t * t1, int type, long value)
+{
+ switch (type) {
+ case IFD_PROTOCOL_T1_CHECKSUM_LRC:
+ case IFD_PROTOCOL_T1_CHECKSUM_CRC:
+ t1_set_checksum(t1, type);
+ break;
+ case IFD_PROTOCOL_T1_IFSC:
+ t1->ifsc = value;
+ break;
+ case IFD_PROTOCOL_T1_IFSD:
+ t1->ifsd = value;
+ break;
+ case IFD_PROTOCOL_T1_STATE:
+ t1->state = value;
+ break;
+ case IFD_PROTOCOL_T1_MORE:
+ t1->more = value;
+ break;
+ default:
+ DEBUG_INFO2("Unsupported parameter %d", type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Send an APDU through T=1
+ */
+int t1_transceive(t1_state_t * t1, unsigned int dad,
+ const void *snd_buf, size_t snd_len,
+ void *rcv_buf, size_t rcv_len)
+{
+ ct_buf_t sbuf, rbuf, tbuf;
+ unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
+ unsigned int slen, retries, resyncs;
+ size_t last_send = 0;
+
+ if (snd_len == 0)
+ return -1;
+
+ /* we can't talk to a dead card / reader. Reset it! */
+ if (t1->state == DEAD)
+ {
+ DEBUG_CRITICAL("T=1 state machine is DEAD. Reset the card first.");
+ return -1;
+ }
+
+ t1->state = SENDING;
+ retries = t1->retries;
+ resyncs = 3;
+
+ /* Initialize send/recv buffer */
+ ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
+ ct_buf_init(&rbuf, rcv_buf, rcv_len);
+
+ /* Send the first block */
+ slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);
+
+ while (1) {
+ unsigned char pcb;
+ int n;
+
+ retries--;
+
+ n = t1_xcv(t1, sdata, slen, sizeof(sdata));
+ if (-2 == n)
+ {
+ DEBUG_COMM("Parity error");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_EDC_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ if (n < 0) {
+ DEBUG_CRITICAL("fatal: transmit/receive failed");
+ t1->state = DEAD;
+ goto error;
+ }
+
+ if ((sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
+ || (sdata[LEN] == 0xFF)) /* length == 0xFF (illegal) */
+ {
+ DEBUG_COMM("R-BLOCK required");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ if (!t1_verify_checksum(t1, sdata, n)) {
+ DEBUG_COMM("checksum failed");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_EDC_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ pcb = sdata[PCB];
+ switch (t1_block_type(pcb)) {
+ case T1_R_BLOCK:
+ if ((sdata[LEN] != 0x00) /* length != 0x00 (illegal) */
+ || (pcb & 0x20) /* b6 of pcb is set */
+ )
+ {
+ DEBUG_COMM("R-Block required");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ if (((t1_seq(pcb) != t1->ns) /* wrong sequence number & no bit more */
+ && ! t1->more)
+ )
+ {
+ DEBUG_COMM4("received: %d, expected: %d, more: %d",
+ t1_seq(pcb), t1->ns, t1->more);
+
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ DEBUG_COMM("R-Block required");
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ if (t1->state == RECEIVING) {
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
+ {
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ DEBUG_COMM("");
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK,
+ NULL, NULL);
+ break;
+ }
+
+ /* If the card terminal requests the next
+ * sequence number, it received the previous
+ * block successfully */
+ if (t1_seq(pcb) != t1->ns) {
+ ct_buf_get(&sbuf, NULL, last_send);
+ last_send = 0;
+ t1->ns ^= 1;
+ }
+
+ /* If there's no data available, the ICC
+ * shouldn't be asking for more */
+ if (ct_buf_avail(&sbuf) == 0)
+ goto resync;
+
+ slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
+ &sbuf, &last_send);
+ break;
+
+ case T1_I_BLOCK:
+ /* The first I-block sent by the ICC indicates
+ * the last block we sent was received successfully. */
+ if (t1->state == SENDING) {
+ DEBUG_COMM("");
+ ct_buf_get(&sbuf, NULL, last_send);
+ last_send = 0;
+ t1->ns ^= 1;
+ }
+
+ t1->state = RECEIVING;
+
+ /* If the block sent by the card doesn't match
+ * what we expected it to send, reply with
+ * an R block */
+ if (t1_seq(pcb) != t1->nr) {
+ DEBUG_COMM("wrong nr");
+
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ t1->nr ^= 1;
+
+ if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
+ {
+ DEBUG_CRITICAL2("buffer overrun by %d bytes", sdata[LEN] - (rbuf.size - rbuf.tail));
+ goto error;
+ }
+
+ if ((pcb & T1_MORE_BLOCKS) == 0)
+ goto done;
+
+ slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
+ break;
+
+ case T1_S_BLOCK:
+ if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
+ /* ISO 7816-3 Rule 6.2 */
+ DEBUG_COMM("S-Block answer received");
+ /* ISO 7816-3 Rule 6.3 */
+ t1->state = SENDING;
+ last_send = 0;
+ resyncs = 3;
+ retries = t1->retries;
+ ct_buf_init(&rbuf, rcv_buf, rcv_len);
+ slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
+ &sbuf, &last_send);
+ continue;
+ }
+
+ if (T1_S_IS_RESPONSE(pcb))
+ {
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ DEBUG_CRITICAL("wrong response S-BLOCK received");
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ ct_buf_init(&tbuf, sblk, sizeof(sblk));
+
+ DEBUG_COMM("S-Block request received");
+ switch (T1_S_TYPE(pcb)) {
+ case T1_S_RESYNC:
+ if (sdata[LEN] != 0)
+ {
+ DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ DEBUG_COMM("Resync requested");
+ /* the card is not allowed to send a resync. */
+ goto resync;
+
+ case T1_S_ABORT:
+ if (sdata[LEN] != 0)
+ {
+ DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ /* ISO 7816-3 Rule 9 */
+ DEBUG_CRITICAL("abort requested");
+ break;
+
+ case T1_S_IFS:
+ if (sdata[LEN] != 1)
+ {
+ DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ DEBUG_CRITICAL2("CT sent S-block with ifs=%u", sdata[DATA]);
+ if (sdata[DATA] == 0)
+ goto resync;
+ t1->ifsc = sdata[DATA];
+ ct_buf_putc(&tbuf, sdata[DATA]);
+ break;
+
+ case T1_S_WTX:
+ if (sdata[LEN] != 1)
+ {
+ DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ DEBUG_COMM2("CT sent S-block with wtx=%u", sdata[DATA]);
+ t1->wtx = sdata[DATA];
+ ct_buf_putc(&tbuf, sdata[DATA]);
+ break;
+
+ default:
+ DEBUG_CRITICAL2("T=1: Unknown S block type 0x%02x", T1_S_TYPE(pcb));
+ goto resync;
+ }
+
+ slen = t1_build(t1, sdata, dad,
+ T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(pcb),
+ &tbuf, NULL);
+ }
+
+ /* Everything went just splendid */
+ retries = t1->retries;
+ continue;
+
+resync:
+ /* the number or resyncs is limited, too */
+ /* ISO 7816-3 Rule 6.4 */
+ if (resyncs == 0)
+ goto error;
+
+ /* ISO 7816-3 Rule 6 */
+ resyncs--;
+ t1->ns = 0;
+ t1->nr = 0;
+ slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
+ NULL);
+ t1->state = RESYNCH;
+ t1->more = FALSE;
+ retries = 1;
+ continue;
+ }
+
+done:
+ return ct_buf_avail(&rbuf);
+
+error:
+ t1->state = DEAD;
+ return -1;
+}
+
+static unsigned t1_block_type(unsigned char pcb)
+{
+ switch (pcb & 0xC0) {
+ case T1_R_BLOCK:
+ return T1_R_BLOCK;
+ case T1_S_BLOCK:
+ return T1_S_BLOCK;
+ default:
+ return T1_I_BLOCK;
+ }
+}
+
+static unsigned int t1_seq(unsigned char pcb)
+{
+ switch (pcb & 0xC0) {
+ case T1_R_BLOCK:
+ return (pcb >> T1_R_SEQ_SHIFT) & 1;
+ case T1_S_BLOCK:
+ return 0;
+ default:
+ return (pcb >> T1_I_SEQ_SHIFT) & 1;
+ }
+}
+
+unsigned int t1_build(t1_state_t * t1, unsigned char *block,
+ unsigned char dad, unsigned char pcb,
+ ct_buf_t *bp, size_t *lenp)
+{
+ unsigned int len;
+ char more = FALSE;
+
+ len = bp ? ct_buf_avail(bp) : 0;
+ if (len > t1->ifsc) {
+ pcb |= T1_MORE_BLOCKS;
+ len = t1->ifsc;
+ more = TRUE;
+ }
+
+ /* Add the sequence number */
+ switch (t1_block_type(pcb)) {
+ case T1_R_BLOCK:
+ pcb |= t1->nr << T1_R_SEQ_SHIFT;
+ break;
+ case T1_I_BLOCK:
+ pcb |= t1->ns << T1_I_SEQ_SHIFT;
+ t1->more = more;
+ DEBUG_COMM2("more bit: %d", more);
+ break;
+ }
+
+ block[0] = dad;
+ block[1] = pcb;
+ block[2] = len;
+
+ if (len)
+ memcpy(block + 3, ct_buf_head(bp), len);
+ if (lenp)
+ *lenp = len;
+
+ len = t1_compute_checksum(t1, block, len + 3);
+
+ /* memorize the last sent block */
+ /* only 4 bytes since we are only interesed in R-blocks */
+ memcpy(t1->previous_block, block, 4);
+
+ return len;
+}
+
+static unsigned int
+t1_rebuild(t1_state_t *t1, unsigned char *block)
+{
+ unsigned char pcb = t1 -> previous_block[1];
+
+ /* copy the last sent block */
+ if (T1_R_BLOCK == t1_block_type(pcb))
+ memcpy(block, t1 -> previous_block, 4);
+ else
+ {
+ DEBUG_CRITICAL2("previous block was not R-Block: %02X", pcb);
+ return 0;
+ }
+
+ return 4;
+}
+
+/*
+ * Build/verify checksum
+ */
+static unsigned int t1_compute_checksum(t1_state_t * t1,
+ unsigned char *data, size_t len)
+{
+ return len + t1->checksum(data, len, data + len);
+}
+
+static int t1_verify_checksum(t1_state_t * t1, unsigned char *rbuf,
+ size_t len)
+{
+ unsigned char csum[2];
+ int m, n;
+
+ m = len - t1->rc_bytes;
+ n = t1->rc_bytes;
+
+ if (m < 0)
+ return 0;
+
+ t1->checksum(rbuf, m, csum);
+ if (!memcmp(rbuf + m, csum, n))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Send/receive block
+ */
+static int t1_xcv(t1_state_t * t1, unsigned char *block, size_t slen,
+ size_t rmax)
+{
+ int n;
+ _ccid_descriptor *ccid_desc ;
+ int oldReadTimeout;
+ unsigned int rmax_int;
+
+ DEBUG_XXD("sending: ", block, slen);
+
+ ccid_desc = get_ccid_descriptor(t1->lun);
+ oldReadTimeout = ccid_desc->readTimeout;
+
+ if (t1->wtx > 1)
+ {
+ /* set the new temporary timeout at WTX card request */
+ ccid_desc->readTimeout *= t1->wtx;
+ DEBUG_INFO2("New timeout at WTX request: %d sec",
+ ccid_desc->readTimeout);
+ }
+
+ if (isCharLevel(t1->lun))
+ {
+ rmax = 3;
+
+ n = CCID_Transmit(t1 -> lun, slen, block, rmax, t1->wtx);
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ /* the second argument of CCID_Receive() is (unsigned int *)
+ * so we can't use &rmax since &rmax is a (size_t *) and may not
+ * be the same on 64-bits architectures for example (iMac G5) */
+ rmax_int = rmax;
+ n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);
+
+ if (n == IFD_PARITY_ERROR)
+ return -2;
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ rmax = block[2] + 1;
+
+ n = CCID_Transmit(t1 -> lun, 0, block, rmax, t1->wtx);
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ rmax_int = rmax;
+ n = CCID_Receive(t1 -> lun, &rmax_int, &block[3], NULL);
+ rmax = rmax_int;
+ if (n == IFD_PARITY_ERROR)
+ return -2;
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ n = rmax + 3;
+ }
+ else
+ {
+ n = CCID_Transmit(t1 -> lun, slen, block, 0, t1->wtx);
+ t1->wtx = 0; /* reset to default value */
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ /* Get the response en bloc */
+ rmax_int = rmax;
+ n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);
+ rmax = rmax_int;
+ if (n == IFD_PARITY_ERROR)
+ return -2;
+ if (n != IFD_SUCCESS)
+ return -1;
+
+ n = rmax;
+ }
+
+ if (n >= 0)
+ {
+ int m;
+
+ m = block[2] + 3 + t1->rc_bytes;
+ if (m < n)
+ n = m;
+ }
+
+ if (n >= 0)
+ DEBUG_XXD("received: ", block, n);
+
+ /* Restore initial timeout */
+ ccid_desc->readTimeout = oldReadTimeout;
+
+ return n;
+}
+
+int t1_negotiate_ifsd(t1_state_t * t1, unsigned int dad, int ifsd)
+{
+ ct_buf_t sbuf;
+ unsigned char sdata[T1_BUFFER_SIZE];
+ unsigned int slen;
+ unsigned int retries;
+ size_t snd_len;
+ int n;
+ unsigned char snd_buf[1];
+
+ retries = t1->retries;
+
+ /* S-block IFSD request */
+ snd_buf[0] = ifsd;
+ snd_len = 1;
+
+ /* Initialize send/recv buffer */
+ ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
+
+ while (TRUE)
+ {
+ /* Build the block */
+ slen = t1_build(t1, sdata, 0, T1_S_BLOCK | T1_S_IFS, &sbuf, NULL);
+
+ /* Send the block */
+ n = t1_xcv(t1, sdata, slen, sizeof(sdata));
+
+ retries--;
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries <= 0)
+ goto error;
+
+ if (-1 == n)
+ {
+ DEBUG_CRITICAL("fatal: transmit/receive failed");
+ goto error;
+ }
+
+ if ((-2 == n) /* Parity error */
+ || (sdata[DATA] != ifsd) /* Wrong ifsd received */
+ || (sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
+ || (!t1_verify_checksum(t1, sdata, n)) /* checksum failed */
+ || (n != 4 + (int)t1->rc_bytes) /* wrong frame length */
+ || (sdata[LEN] != 1) /* wrong data length */
+ || (sdata[PCB] != (T1_S_BLOCK | T1_S_RESPONSE | T1_S_IFS))) /* wrong PCB */
+ continue;
+
+ /* no more error */
+ goto done;
+ }
+
+done:
+ return n;
+
+error:
+ t1->state = DEAD;
+ return -1;
+}
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h b/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h
new file mode 100644
index 0000000..a4732ed
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h
@@ -0,0 +1,85 @@
+/*
+ proto-t1.h: header file for proto-t1.c
+ Copyright (C) 2004 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/* $Id: proto-t1.h 6975 2014-09-04 11:33:05Z rousseau $ */
+
+#ifndef __PROTO_T1_H__
+#define __PROTO_T1_H__
+
+#include <config.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include "buffer.h"
+
+/* T=1 protocol constants */
+#define T1_I_BLOCK 0x00
+#define T1_R_BLOCK 0x80
+#define T1_S_BLOCK 0xC0
+#define T1_MORE_BLOCKS 0x20
+
+enum {
+ IFD_PROTOCOL_RECV_TIMEOUT = 0x0000,
+ IFD_PROTOCOL_T1_BLOCKSIZE,
+ IFD_PROTOCOL_T1_CHECKSUM_CRC,
+ IFD_PROTOCOL_T1_CHECKSUM_LRC,
+ IFD_PROTOCOL_T1_IFSC,
+ IFD_PROTOCOL_T1_IFSD,
+ IFD_PROTOCOL_T1_STATE,
+ IFD_PROTOCOL_T1_MORE
+};
+
+#define T1_BUFFER_SIZE (3 + 254 + 2)
+
+/* see /usr/include/PCSC/ifdhandler.h for other values
+ * this one is for internal use only */
+#define IFD_PARITY_ERROR 699
+
+typedef struct {
+ int lun;
+ int state;
+
+ unsigned char ns; /* reader side */
+ unsigned char nr; /* card side */
+ unsigned int ifsc;
+ unsigned int ifsd;
+
+ unsigned char wtx;
+ unsigned int retries;
+ unsigned int rc_bytes;
+
+ unsigned int (*checksum)(const uint8_t *, size_t, unsigned char *);
+
+ char more; /* more data bit */
+ unsigned char previous_block[4]; /* to store the last R-block */
+} t1_state_t;
+
+int t1_transceive(t1_state_t *t1, unsigned int dad,
+ const void *snd_buf, size_t snd_len,
+ void *rcv_buf, size_t rcv_len);
+int t1_init(t1_state_t *t1, int lun);
+void t1_release(t1_state_t *t1);
+int t1_set_param(t1_state_t *t1, int type, long value);
+int t1_negotiate_ifsd(t1_state_t *t1, unsigned int dad, int ifsd);
+unsigned int t1_build(t1_state_t *, unsigned char *,
+ unsigned char, unsigned char, ct_buf_t *, size_t *);
+
+#endif
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING
new file mode 100644
index 0000000..68dc4c5
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING
@@ -0,0 +1,505 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README
new file mode 100644
index 0000000..49c38bc
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README
@@ -0,0 +1,14 @@
+All the files in the src/protocol_t1/ directory comes from Carlos
+Prados Towitoko smartcard readers driver.
+
+I (Ludovic Rousseau) hacked the source files a bit to include them in my
+CCID driver. So bugs are mine and not Carlos' fault. As indicated in
+the source files headers this code is protected by the GNU Lesser
+General Public License.
+
+I used version 2.0.7 of Carlos driver available at
+http://www.geocities.com/cprados/
+
+I added the function ATR_GetDefaultProtocol() in towitoko/atr.c
+
+$Id: README 1001 2004-06-30 13:49:38Z rousseau $
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c
new file mode 100644
index 0000000..6968a5c
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c
@@ -0,0 +1,365 @@
+/*
+ atr.c
+ ISO 7816 ICC's answer to reset abstract data type implementation
+
+ This file is part of the Unix driver for Towitoko smartcard readers
+ Copyright (C) 2000 Carlos Prados <***@yahoo.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <config.h>
+
+#include "atr.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "debug.h"
+
+/*
+ * Not exported variables definition
+ */
+
+static unsigned
+atr_num_ib_table[16] =
+{
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
+};
+
+/*
+ * Exported variables definition
+ */
+
+static unsigned
+atr_f_table[16] =
+{
+ 372, 372, 558, 744, 1116, 1488, 1860, 0, 0, 512, 768, 1024, 1536, 2048, 0, 0
+};
+
+static unsigned
+atr_d_table[16] =
+{
+ 0, 1, 2, 4, 8, 16, 32, 64, 12, 20, 0, 0, 0, 0, 0, 0
+};
+
+static unsigned
+atr_i_table[4] =
+{
+ 25, 50, 100, 0
+};
+
+/*
+ * Exported functions definition
+ */
+
+int
+ATR_InitFromArray (ATR_t * atr, const BYTE atr_buffer[ATR_MAX_SIZE], unsigned length)
+{
+ BYTE TDi;
+ unsigned pointer = 0, pn = 0;
+
+ /* Check size of buffer */
+ if (length < 2)
+ return (ATR_MALFORMED);
+
+ /* Store T0 and TS */
+ atr->TS = atr_buffer[0];
+
+ atr->T0 = TDi = atr_buffer[1];
+ pointer = 1;
+
+ /* Store number of historical bytes */
+ atr->hbn = TDi & 0x0F;
+
+ /* TCK is not present by default */
+ (atr->TCK).present = FALSE;
+
+ /* Extract interface bytes */
+ while (pointer < length)
+ {
+ /* Check buffer is long enought */
+ if (pointer + atr_num_ib_table[(0xF0 & TDi) >> 4] >= length)
+ {
+ return (ATR_MALFORMED);
+ }
+ /* Check TAi is present */
+ if ((TDi | 0xEF) == 0xFF)
+ {
+ pointer++;
+ atr->ib[pn][ATR_INTERFACE_BYTE_TA].value = atr_buffer[pointer];
+ atr->ib[pn][ATR_INTERFACE_BYTE_TA].present = TRUE;
+ }
+ else
+ atr->ib[pn][ATR_INTERFACE_BYTE_TA].present = FALSE;
+ /* Check TBi is present */
+ if ((TDi | 0xDF) == 0xFF)
+ {
+ pointer++;
+ atr->ib[pn][ATR_INTERFACE_BYTE_TB].value = atr_buffer[pointer];
+ atr->ib[pn][ATR_INTERFACE_BYTE_TB].present = TRUE;
+ }
+ else
+ atr->ib[pn][ATR_INTERFACE_BYTE_TB].present = FALSE;
+
+ /* Check TCi is present */
+ if ((TDi | 0xBF) == 0xFF)
+ {
+ pointer++;
+ atr->ib[pn][ATR_INTERFACE_BYTE_TC].value = atr_buffer[pointer];
+ atr->ib[pn][ATR_INTERFACE_BYTE_TC].present = TRUE;
+ }
+ else
+ atr->ib[pn][ATR_INTERFACE_BYTE_TC].present = FALSE;
+
+ /* Read TDi if present */
+ if ((TDi | 0x7F) == 0xFF)
+ {
+ pointer++;
+ TDi = atr->ib[pn][ATR_INTERFACE_BYTE_TD].value = atr_buffer[pointer];
+ atr->ib[pn][ATR_INTERFACE_BYTE_TD].present = TRUE;
+ (atr->TCK).present = ((TDi & 0x0F) != ATR_PROTOCOL_TYPE_T0);
+ pn++;
+ if (pn >= ATR_MAX_PROTOCOLS)
+ return (ATR_MALFORMED);
+ }
+ else
+ {
+ atr->ib[pn][ATR_INTERFACE_BYTE_TD].present = FALSE;
+ break;
+ }
+ }
+
+ /* Store number of protocols */
+ atr->pn = pn + 1;
+
+ /* Store historical bytes */
+ if (pointer + atr->hbn >= length)
+ return (ATR_MALFORMED);
+
+ memcpy (atr->hb, atr_buffer + pointer + 1, atr->hbn);
+ pointer += (atr->hbn);
+
+ /* Store TCK */
+ if ((atr->TCK).present)
+ {
+
+ if (pointer + 1 >= length)
+ return (ATR_MALFORMED);
+
+ pointer++;
+
+ (atr->TCK).value = atr_buffer[pointer];
+ }
+
+ atr->length = pointer + 1;
+ return (ATR_OK);
+}
+
+int
+ATR_GetConvention (ATR_t * atr, int *convention)
+{
+ if (atr->TS == 0x3B)
+ (*convention) = ATR_CONVENTION_DIRECT;
+ else if (atr->TS == 0x3F)
+ (*convention) = ATR_CONVENTION_INVERSE;
+ else
+ return (ATR_MALFORMED);
+ return (ATR_OK);
+}
+
+int
+ATR_GetIntegerValue (ATR_t * atr, int name, BYTE * value)
+{
+ int ret;
+
+ if (name == ATR_INTEGER_VALUE_FI)
+ {
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TA].present)
+ {
+ (*value) = (atr->ib[0][ATR_INTERFACE_BYTE_TA].value & 0xF0) >> 4;
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+
+ else if (name == ATR_INTEGER_VALUE_DI)
+ {
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TA].present)
+ {
+ (*value) = (atr->ib[0][ATR_INTERFACE_BYTE_TA].value & 0x0F);
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+
+ else if (name == ATR_INTEGER_VALUE_II)
+ {
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TB].present)
+ {
+ (*value) = (atr->ib[0][ATR_INTERFACE_BYTE_TB].value & 0x60) >> 5;
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+
+ else if (name == ATR_INTEGER_VALUE_PI1)
+ {
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TB].present)
+ {
+ (*value) = (atr->ib[0][ATR_INTERFACE_BYTE_TB].value & 0x1F);
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+
+ else if (name == ATR_INTEGER_VALUE_PI2)
+ {
+ if (atr->ib[1][ATR_INTERFACE_BYTE_TB].present)
+ {
+ (*value) = atr->ib[1][ATR_INTERFACE_BYTE_TB].value;
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+
+ else if (name == ATR_INTEGER_VALUE_N)
+ {
+ if (atr->ib[0][ATR_INTERFACE_BYTE_TC].present)
+ {
+ (*value) = atr->ib[0][ATR_INTERFACE_BYTE_TC].value;
+ ret = ATR_OK;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+ }
+ else
+ ret = ATR_NOT_FOUND;
+
+ return ret;
+}
+
+int
+ATR_GetParameter (ATR_t * atr, int name, double *parameter)
+{
+ BYTE FI, DI, II, PI1, PI2, N;
+
+ if (name == ATR_PARAMETER_F)
+ {
+ if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_FI, &FI) == ATR_OK)
+ (*parameter) = (double) (atr_f_table[FI]);
+ else
+ (*parameter) = (double) ATR_DEFAULT_F;
+ return (ATR_OK);
+ }
+
+ else if (name == ATR_PARAMETER_D)
+ {
+ if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_DI, &DI) == ATR_OK)
+ (*parameter) = (double) (atr_d_table[DI]);
+ else
+ (*parameter) = (double) ATR_DEFAULT_D;
+ return (ATR_OK);
+ }
+
+ else if (name == ATR_PARAMETER_I)
+ {
+ if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_II, &II) == ATR_OK)
+ (*parameter) = (double) (atr_i_table[II]);
+ else
+ (*parameter) = ATR_DEFAULT_I;
+ return (ATR_OK);
+ }
+
+ else if (name == ATR_PARAMETER_P)
+ {
+ if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_PI2, &PI2) == ATR_OK)
+ (*parameter) = (double) PI2;
+ else if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_PI1, &PI1) == ATR_OK)
+ (*parameter) = (double) PI1;
+ else
+ (*parameter) = (double) ATR_DEFAULT_P;
+ return (ATR_OK);
+ }
+
+ else if (name == ATR_PARAMETER_N)
+ {
+ if (ATR_GetIntegerValue (atr, ATR_INTEGER_VALUE_N, &N) == ATR_OK)
+ (*parameter) = (double) N;
+ else
+ (*parameter) = (double) ATR_DEFAULT_N;
+ return (ATR_OK);
+ }
+
+ return (ATR_NOT_FOUND);
+}
+
+/*
+ * This function was greatly inspired by ATRDecodeAtr() and
+ * PHGetDefaultProtocol() from pcsc-lite
+ *
+ * It was rewritten by Ludovic Rousseau, 2004
+ */
+#define PROTOCOL_UNSET -1
+int ATR_GetDefaultProtocol(ATR_t * atr, int *protocol, int *availableProtocols)
+{
+ int i;
+
+ /* default value */
+ *protocol = PROTOCOL_UNSET;
+ if (availableProtocols)
+ *availableProtocols = 0;
+
+ for (i=0; i<ATR_MAX_PROTOCOLS; i++)
+ if (atr->ib[i][ATR_INTERFACE_BYTE_TD].present)
+ {
+ int T = atr->ib[i][ATR_INTERFACE_BYTE_TD].value & 0x0F;
+
+ DEBUG_COMM2("T=%d Protocol Found", T);
+ if (availableProtocols)
+ *availableProtocols |= 1 << T;
+
+ if (PROTOCOL_UNSET == *protocol)
+ {
+ /* set to the first protocol byte found */
+ *protocol = T;
+ DEBUG_COMM2("default protocol: T=%d", *protocol);
+ }
+ }
+
+ /* specific mode if TA2 present */
+ if (atr->ib[1][ATR_INTERFACE_BYTE_TA].present)
+ {
+ *protocol = atr->ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F;
+ if (availableProtocols)
+ *availableProtocols = 1 << *protocol;
+ DEBUG_COMM2("specific mode found: T=%d", *protocol);
+ }
+
+ if (PROTOCOL_UNSET == *protocol)
+ {
+ DEBUG_INFO1("no default protocol found in ATR. Using T=0");
+ *protocol = ATR_PROTOCOL_TYPE_T0;
+ if (availableProtocols)
+ *availableProtocols = 1 << *protocol;
+ }
+
+ return ATR_OK;
+}
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h
new file mode 100644
index 0000000..23207f6
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h
@@ -0,0 +1,111 @@
+/*
+ atr.h
+ ISO 7816 ICC's answer to reset abstract data type definitions
+
+ This file is part of the Unix driver for Towitoko smartcard readers
+ Copyright (C) 2000 Carlos Prados <***@yahoo.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef _ATR_
+#define _ATR_
+
+#include "defines.h"
+
+/*
+ * Exported constants definition
+ */
+
+/* Return values */
+#define ATR_OK 0 /* ATR could be parsed and data returned */
+#define ATR_NOT_FOUND 1 /* Data not present in ATR */
+#define ATR_MALFORMED 2 /* ATR could not be parsed */
+#define ATR_IO_ERROR 3 /* I/O stream error */
+
+/* Paramenters */
+#define ATR_MAX_SIZE 33 /* Maximum size of ATR byte array */
+#define ATR_MAX_HISTORICAL 15 /* Maximum number of historical bytes */
+#define ATR_MAX_PROTOCOLS 7 /* Maximun number of protocols */
+#define ATR_MAX_IB 4 /* Maximum number of interface bytes per protocol */
+#define ATR_CONVENTION_DIRECT 0 /* Direct convention */
+#define ATR_CONVENTION_INVERSE 1 /* Inverse convention */
+#define ATR_PROTOCOL_TYPE_T0 0 /* Protocol type T=0 */
+#define ATR_PROTOCOL_TYPE_T1 1 /* Protocol type T=1 */
+#define ATR_PROTOCOL_TYPE_T2 2 /* Protocol type T=2 */
+#define ATR_PROTOCOL_TYPE_T3 3 /* Protocol type T=3 */
+#define ATR_PROTOCOL_TYPE_T14 14 /* Protocol type T=14 */
+#define ATR_INTERFACE_BYTE_TA 0 /* Interface byte TAi */
+#define ATR_INTERFACE_BYTE_TB 1 /* Interface byte TBi */
+#define ATR_INTERFACE_BYTE_TC 2 /* Interface byte TCi */
+#define ATR_INTERFACE_BYTE_TD 3 /* Interface byte TDi */
+#define ATR_PARAMETER_F 0 /* Parameter F */
+#define ATR_PARAMETER_D 1 /* Parameter D */
+#define ATR_PARAMETER_I 2 /* Parameter I */
+#define ATR_PARAMETER_P 3 /* Parameter P */
+#define ATR_PARAMETER_N 4 /* Parameter N */
+#define ATR_INTEGER_VALUE_FI 0 /* Integer value FI */
+#define ATR_INTEGER_VALUE_DI 1 /* Integer value DI */
+#define ATR_INTEGER_VALUE_II 2 /* Integer value II */
+#define ATR_INTEGER_VALUE_PI1 3 /* Integer value PI1 */
+#define ATR_INTEGER_VALUE_N 4 /* Integer value N */
+#define ATR_INTEGER_VALUE_PI2 5 /* Integer value PI2 */
+
+/* Default values for paramenters */
+#define ATR_DEFAULT_F 372
+#define ATR_DEFAULT_D 1
+#define ATR_DEFAULT_I 50
+#define ATR_DEFAULT_N 0
+#define ATR_DEFAULT_P 5
+
+/*
+ * Exported data types definition
+ */
+
+typedef struct
+{
+ unsigned length;
+ BYTE TS;
+ BYTE T0;
+ struct
+ {
+ BYTE value;
+ bool present;
+ }
+ ib[ATR_MAX_PROTOCOLS][ATR_MAX_IB], TCK;
+ unsigned pn;
+ BYTE hb[ATR_MAX_HISTORICAL];
+ unsigned hbn;
+}
+ATR_t;
+
+/*
+ * Exported functions declaraton
+ */
+
+/* Initialization */
+extern int ATR_InitFromArray(ATR_t * atr, const BYTE buffer[ATR_MAX_SIZE],
+ unsigned length);
+
+/* General smartcard characteristics */
+extern int ATR_GetConvention(ATR_t * atr, /*@out@*/ int *convention);
+extern int ATR_GetDefaultProtocol(ATR_t * atr, /*@out@*/ int *protocol, int *availableProtocols);
+
+/* ATR parameters and integer values */
+extern int ATR_GetIntegerValue(ATR_t * atr, int name, BYTE * value);
+extern int ATR_GetParameter(ATR_t * atr, int name, /*@out@*/ double *parameter);
+
+#endif /* _ATR_ */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h
new file mode 100644
index 0000000..abd5dbe
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h
@@ -0,0 +1,56 @@
+/*
+ defines.h
+
+ This file is part of the Unix driver for Towitoko smartcard readers
+ Copyright (C) 2000 Carlos Prados <***@yahoo.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef DEFINES_H
+#define DEFINES_H
+
+/*
+ * Get configuration information
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+ * Boolean constants
+ */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*
+ * Type definitions
+ */
+
+#include <wintypes.h>
+
+#ifndef __cplusplus
+typedef int bool;
+#endif
+
+#endif /* DEFINES_H */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c
new file mode 100644
index 0000000..cfe8e8d
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c
@@ -0,0 +1,136 @@
+/*
+ pps.c
+ Protocol Parameters Selection
+
+ This file is part of the Unix driver for Towitoko smartcard readers
+ Copyright (C) 2000 2001 Carlos Prados <***@yahoo.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "pps.h"
+#include "atr.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <ifdhandler.h>
+
+#include "commands.h"
+#include "defs.h"
+#include "debug.h"
+
+/*
+ * Not exported funtions declaration
+ */
+
+static bool PPS_Match (BYTE * request, unsigned len_request, BYTE * reply, unsigned len_reply);
+
+static unsigned PPS_GetLength (BYTE * block);
+
+static BYTE PPS_GetPCK (BYTE * block, unsigned length);
+
+int
+PPS_Exchange (int lun, BYTE * params, unsigned *length, unsigned char *pps1)
+{
+ BYTE confirm[PPS_MAX_LENGTH];
+ unsigned len_request, len_confirm;
+ int ret;
+
+ len_request = PPS_GetLength (params);
+ params[len_request - 1] = PPS_GetPCK(params, len_request - 1);
+
+ DEBUG_XXD ("PPS: Sending request: ", params, len_request);
+
+ /* Send PPS request */
+ if (CCID_Transmit (lun, len_request, params, isCharLevel(lun) ? 4 : 0, 0)
+ != IFD_SUCCESS)
+ return PPS_ICC_ERROR;
+
+ /* Get PPS confirm */
+ len_confirm = sizeof(confirm);
+ if (CCID_Receive (lun, &len_confirm, confirm, NULL) != IFD_SUCCESS)
+ return PPS_ICC_ERROR;
+
+ DEBUG_XXD ("PPS: Receiving confirm: ", confirm, len_confirm);
+
+ if (!PPS_Match (params, len_request, confirm, len_confirm))
+ ret = PPS_HANDSAKE_ERROR;
+ else
+ ret = PPS_OK;
+
+ *pps1 = 0x11; /* default TA1 */
+
+ /* if PPS1 is echoed */
+ if (PPS_HAS_PPS1 (params) && PPS_HAS_PPS1 (confirm))
+ *pps1 = confirm[2];
+
+ /* Copy PPS handsake */
+ memcpy (params, confirm, len_confirm);
+ (*length) = len_confirm;
+
+ return ret;
+}
+
+static bool
+PPS_Match (BYTE * request, unsigned len_request, BYTE * confirm, unsigned len_confirm)
+{
+ /* See if the reply differs from request */
+ if ((len_request == len_confirm) && /* same length */
+ memcmp (request, confirm, len_request)) /* different contents */
+ return FALSE;
+
+ if (len_request < len_confirm) /* confirm longer than request */
+ return FALSE;
+
+ /* See if the card specifies other than default FI and D */
+ if ((PPS_HAS_PPS1 (confirm)) && (confirm[2] != request[2]))
+ return FALSE;
+
+ return TRUE;
+}
+
+static unsigned
+PPS_GetLength (BYTE * block)
+{
+ unsigned length = 3;
+
+ if (PPS_HAS_PPS1 (block))
+ length++;
+
+ if (PPS_HAS_PPS2 (block))
+ length++;
+
+ if (PPS_HAS_PPS3 (block))
+ length++;
+
+ return length;
+}
+
+static BYTE
+PPS_GetPCK (BYTE * block, unsigned length)
+{
+ BYTE pck;
+ unsigned i;
+
+ pck = block[0];
+ for (i = 1; i < length; i++)
+ pck ^= block[i];
+
+ return pck;
+}
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h
new file mode 100644
index 0000000..d9c2ae6
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h
@@ -0,0 +1,71 @@
+/*
+ pps.h
+ Protocol Parameters Selection
+
+ This file is part of the Unix driver for Towitoko smartcard readers
+ Copyright (C) 2000 2001 Carlos Prados <***@yahoo.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _PPS_
+#define _PPS_
+
+#include "defines.h"
+
+/*
+ * Exported constants definition
+ */
+
+#define PPS_OK 0 /* Negotiation OK */
+#define PPS_ICC_ERROR 1 /* Comunication error */
+#define PPS_HANDSAKE_ERROR 2 /* Agreement not reached */
+#define PPS_PROTOCOL_ERROR 3 /* Error starting protocol */
+#define PPS_MAX_LENGTH 6
+
+#define PPS_HAS_PPS1(block) ((block[1] & 0x10) == 0x10)
+#define PPS_HAS_PPS2(block) ((block[1] & 0x20) == 0x20)
+#define PPS_HAS_PPS3(block) ((block[1] & 0x40) == 0x40)
+
+/*
+ * Exported data types definition
+ */
+
+typedef struct
+{
+ double f;
+ double d;
+ double n;
+ BYTE t;
+}
+PPS_ProtocolParameters;
+
+typedef struct
+{
+ int icc;
+ void *protocol;
+ PPS_ProtocolParameters parameters;
+}
+PPS;
+
+/*
+ * Exported functions declaration
+ */
+
+int PPS_Exchange (int lun, BYTE * params, /*@out@*/ unsigned *length,
+ unsigned char *pps1);
+
+#endif /* _PPS_ */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/utils.c b/MdeModulePkg/Library/SmartCardReader/libccid/utils.c
new file mode 100644
index 0000000..9b35ee7
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/utils.c
@@ -0,0 +1,85 @@
+/*
+ utils.c:
+ Copyright (C) 2003-2008 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: utils.c 6975 2014-09-04 11:33:05Z rousseau $
+ */
+
+#include <pcsclite.h>
+
+#include <config.h>
+#include "ccid.h"
+#include "defs.h"
+#include "ccid_ifdhandler.h"
+#include "utils.h"
+#include "debug.h"
+
+int ReaderIndex[CCID_DRIVER_MAX_READERS];
+
+void InitReaderIndex(void)
+{
+ int i;
+
+ for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
+ ReaderIndex[i] = -1;
+} /* InitReaderIndex */
+
+int GetNewReaderIndex(const int Lun)
+{
+ int i;
+
+ /* check that Lun is NOT already used */
+ for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
+ if (Lun == ReaderIndex[i])
+ break;
+
+ if (i < CCID_DRIVER_MAX_READERS)
+ {
+ DEBUG_CRITICAL2("Lun: %d is already used", Lun);
+ return -1;
+ }
+
+ for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
+ if (-1 == ReaderIndex[i])
+ {
+ ReaderIndex[i] = Lun;
+ return i;
+ }
+
+ DEBUG_CRITICAL("ReaderIndex[] is full");
+ return -1;
+} /* GetReaderIndex */
+
+int LunToReaderIndex(const int Lun)
+{
+ int i;
+
+ for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
+ if (Lun == ReaderIndex[i])
+ return i;
+
+ DEBUG_CRITICAL2("Lun: %X not found", Lun);
+ return -1;
+} /* LunToReaderIndex */
+
+void ReleaseReaderIndex(const int index)
+{
+ ReaderIndex[index] = -1;
+} /* ReleaseReaderIndex */
+
diff --git a/MdeModulePkg/Library/SmartCardReader/libccid/utils.h b/MdeModulePkg/Library/SmartCardReader/libccid/utils.h
new file mode 100644
index 0000000..3f21302
--- /dev/null
+++ b/MdeModulePkg/Library/SmartCardReader/libccid/utils.h
@@ -0,0 +1,33 @@
+/*
+ utils.c:
+ Copyright (C) 2003-2009 Ludovic Rousseau
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+ * $Id: utils.h 4973 2010-06-01 09:43:29Z rousseau $
+ */
+
+#ifndef TRUE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+void InitReaderIndex(void);
+int GetNewReaderIndex(const int Lun);
+int LunToReaderIndex(int Lun);
+void ReleaseReaderIndex(const int idx);
+
--
2.1.4


------------------------------------------------------------------------------
Tian, Feng
2015-06-11 01:46:46 UTC
Permalink
Ludovic,

The license issue is the biggest concern. EDKII project is BSD license, but your proposed patch 1 is using LGPL license which may corrupt EDKII project.

Thanks
Feng

-----Original Message-----
From: Ludovic Rousseau [mailto:***@gmail.com]
Sent: Thursday, June 11, 2015 02:28
To: edk2-***@lists.sourceforge.net
Cc: Ludovic Rousseau
Subject: [edk2] [PATCH 0/4] Add an implementation of EFI_SMART_CARD_READER_PROTOCOL

This patch serie provides an implementation for the EFI_SMART_CARD_READER_PROTOCOL added in UEFI version 2.5.

It is a port of my CCID driver from Unix to UEFI. Only part of the code has been specifically written for UEFI and edk2. Only this part of the code follows the coding rules. The idea os to keep most of the code common to edk2 and my original CCID driver so code is easy to backport from one project to the other.

patch 1: are files from the libccid project [1], GNU LGLP v2.1 patch 2: are files from the pcsc-lite project [2], TianoCore Contribution Agreement 1.0 patch 3: are files specifically written for edk2, TianoCore Contribution Agreement 1.0 patch 4: edit MdeModulePkg/MdeModulePkg.dsc to add the driver, TianoCore Contribution Agreement 1.0

The code has been tested on a Dell E6430 with an internal Broadcom smart card reader and also different external USB smart card readers.

[1] https://pcsclite.alioth.debian.org/ccid.html
[2] https://pcsclite.alioth.debian.org/pcsclite.html


Ludovic Rousseau (4):
MdeModulePkg/SmartCardReader: Add files from the libccid project
MdeModulePkg/SmartCardReader: Add files from pcsc-lite project
MdeModulePkg/SmartCardReader: Implement Smart Card Reader Protocol
MdeModulePkg: add SmartCardReader.inf

MdeModulePkg/Library/SmartCardReader/CcidDriver.c | 819 +++++++ MdeModulePkg/Library/SmartCardReader/CcidDriver.h | 154 ++
.../Library/SmartCardReader/ComponentName.c | 198 ++
.../Library/SmartCardReader/ComponentName.h | 128 ++
.../Library/SmartCardReader/DriverBinding.h | 211 ++
MdeModulePkg/Library/SmartCardReader/License.txt | 87 +
.../Library/SmartCardReader/SmartCardReader.inf | 97 +
.../Library/SmartCardReader/SmartCardReader_impl.c | 453 ++++
.../Library/SmartCardReader/SmartCardReader_impl.h | 94 +
MdeModulePkg/Library/SmartCardReader/config.h | 64 +
MdeModulePkg/Library/SmartCardReader/debug.c | 62 +
MdeModulePkg/Library/SmartCardReader/debuglog.h | 81 +
MdeModulePkg/Library/SmartCardReader/ifdhandler.h | 825 +++++++
.../Library/SmartCardReader/libccid/ccid.c | 659 ++++++
.../Library/SmartCardReader/libccid/ccid.h | 340 +++
.../SmartCardReader/libccid/ccid_ifdhandler.h | 63 +
.../Library/SmartCardReader/libccid/ccid_uefi.c | 470 ++++
.../Library/SmartCardReader/libccid/ccid_uefi.h | 46 +
.../Library/SmartCardReader/libccid/commands.c | 2294 ++++++++++++++++++++
.../Library/SmartCardReader/libccid/commands.h | 64 +
.../Library/SmartCardReader/libccid/debug.c | 157 ++
.../Library/SmartCardReader/libccid/debug.h | 100 +
.../Library/SmartCardReader/libccid/defs.h | 126 ++
.../Library/SmartCardReader/libccid/ifdhandler.c | 2265 +++++++++++++++++++
.../Library/SmartCardReader/libccid/openct/LICENSE | 28 +
.../Library/SmartCardReader/libccid/openct/README | 7 +
.../SmartCardReader/libccid/openct/buffer.c | 73 +
.../SmartCardReader/libccid/openct/buffer.h | 36 +
.../SmartCardReader/libccid/openct/checksum.c | 95 +
.../SmartCardReader/libccid/openct/checksum.h | 37 +
.../SmartCardReader/libccid/openct/proto-t1.c | 800 +++++++
.../SmartCardReader/libccid/openct/proto-t1.h | 85 +
.../SmartCardReader/libccid/towitoko/COPYING | 505 +++++
.../SmartCardReader/libccid/towitoko/README | 14 +
.../Library/SmartCardReader/libccid/towitoko/atr.c | 365 ++++ .../Library/SmartCardReader/libccid/towitoko/atr.h | 111 +
.../SmartCardReader/libccid/towitoko/defines.h | 56 +
.../Library/SmartCardReader/libccid/towitoko/pps.c | 136 ++
.../Library/SmartCardReader/libccid/towitoko/pps.h | 71 +
.../Library/SmartCardReader/libccid/utils.c | 85 +
.../Library/SmartCardReader/libccid/utils.h | 33 +
MdeModulePkg/Library/SmartCardReader/misc.h | 88 +
MdeModulePkg/Library/SmartCardReader/pcsclite.h | 65 +
MdeModulePkg/Library/SmartCardReader/reader.h | 285 +++
MdeModulePkg/Library/SmartCardReader/wintypes.h | 120 +
MdeModulePkg/MdeModulePkg.dsc | 1 +
46 files changed, 12953 insertions(+)
create mode 100644 MdeModulePkg/Library/SmartCardReader/CcidDriver.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/CcidDriver.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/ComponentName.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/ComponentName.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/DriverBinding.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/License.txt
create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader.inf
create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/config.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/debug.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/debuglog.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/ifdhandler.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/commands.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/commands.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/debug.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/debug.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/defs.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/README
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/utils.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/utils.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/misc.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/pcsclite.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/reader.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/wintypes.h

--
2.1.4
El-Haj-Mahmoud, Samer
2015-06-11 01:59:05 UTC
Permalink
I agree that the license is an issue. Having GPL or LGPL code in EDK2 risks implementations that use this code. Even if an implementation choses not to carry this specific driver in binary format, just having the GPL source in the same tree is a risk. What if developers copy fragments of code from the GPL licensed driver and use in another module in the tree that is BSD licensed. Developeers may not pay attention to the license and its implications since EDK2 so far has used only BSD or BSD-like license.



-----Original Message-----
From: Tian, Feng [***@intel.com]
Received: Wednesday, 10 Jun 2015, 9:52PM
To: edk2-***@lists.sourceforge.net [edk2-***@lists.sourceforge.net]
Subject: Re: [edk2] [PATCH 0/4] Add an implementation of EFI_SMART_CARD_READER_PROTOCOL

Ludovic,

The license issue is the biggest concern. EDKII project is BSD license, but your proposed patch 1 is using LGPL license which may corrupt EDKII project.

Thanks
Feng

-----Original Message-----
From: Ludovic Rousseau [mailto:***@gmail.com]
Sent: Thursday, June 11, 2015 02:28
To: edk2-***@lists.sourceforge.net
Cc: Ludovic Rousseau
Subject: [edk2] [PATCH 0/4] Add an implementation of EFI_SMART_CARD_READER_PROTOCOL

This patch serie provides an implementation for the EFI_SMART_CARD_READER_PROTOCOL added in UEFI version 2.5.

It is a port of my CCID driver from Unix to UEFI. Only part of the code has been specifically written for UEFI and edk2. Only this part of the code follows the coding rules. The idea os to keep most of the code common to edk2 and my original CCID driver so code is easy to backport from one project to the other.

patch 1: are files from the libccid project [1], GNU LGLP v2.1 patch 2: are files from the pcsc-lite project [2], TianoCore Contribution Agreement 1.0 patch 3: are files specifically written for edk2, TianoCore Contribution Agreement 1.0 patch 4: edit MdeModulePkg/MdeModulePkg.dsc to add the driver, TianoCore Contribution Agreement 1.0

The code has been tested on a Dell E6430 with an internal Broadcom smart card reader and also different external USB smart card readers.

[1] https://pcsclite.alioth.debian.org/ccid.html
[2] https://pcsclite.alioth.debian.org/pcsclite.html


Ludovic Rousseau (4):
MdeModulePkg/SmartCardReader: Add files from the libccid project
MdeModulePkg/SmartCardReader: Add files from pcsc-lite project
MdeModulePkg/SmartCardReader: Implement Smart Card Reader Protocol
MdeModulePkg: add SmartCardReader.inf

MdeModulePkg/Library/SmartCardReader/CcidDriver.c | 819 +++++++ MdeModulePkg/Library/SmartCardReader/CcidDriver.h | 154 ++
.../Library/SmartCardReader/ComponentName.c | 198 ++
.../Library/SmartCardReader/ComponentName.h | 128 ++
.../Library/SmartCardReader/DriverBinding.h | 211 ++
MdeModulePkg/Library/SmartCardReader/License.txt | 87 +
.../Library/SmartCardReader/SmartCardReader.inf | 97 +
.../Library/SmartCardReader/SmartCardReader_impl.c | 453 ++++
.../Library/SmartCardReader/SmartCardReader_impl.h | 94 +
MdeModulePkg/Library/SmartCardReader/config.h | 64 +
MdeModulePkg/Library/SmartCardReader/debug.c | 62 +
MdeModulePkg/Library/SmartCardReader/debuglog.h | 81 +
MdeModulePkg/Library/SmartCardReader/ifdhandler.h | 825 +++++++
.../Library/SmartCardReader/libccid/ccid.c | 659 ++++++
.../Library/SmartCardReader/libccid/ccid.h | 340 +++
.../SmartCardReader/libccid/ccid_ifdhandler.h | 63 +
.../Library/SmartCardReader/libccid/ccid_uefi.c | 470 ++++
.../Library/SmartCardReader/libccid/ccid_uefi.h | 46 +
.../Library/SmartCardReader/libccid/commands.c | 2294 ++++++++++++++++++++
.../Library/SmartCardReader/libccid/commands.h | 64 +
.../Library/SmartCardReader/libccid/debug.c | 157 ++
.../Library/SmartCardReader/libccid/debug.h | 100 +
.../Library/SmartCardReader/libccid/defs.h | 126 ++
.../Library/SmartCardReader/libccid/ifdhandler.c | 2265 +++++++++++++++++++
.../Library/SmartCardReader/libccid/openct/LICENSE | 28 +
.../Library/SmartCardReader/libccid/openct/README | 7 +
.../SmartCardReader/libccid/openct/buffer.c | 73 +
.../SmartCardReader/libccid/openct/buffer.h | 36 +
.../SmartCardReader/libccid/openct/checksum.c | 95 +
.../SmartCardReader/libccid/openct/checksum.h | 37 +
.../SmartCardReader/libccid/openct/proto-t1.c | 800 +++++++
.../SmartCardReader/libccid/openct/proto-t1.h | 85 +
.../SmartCardReader/libccid/towitoko/COPYING | 505 +++++
.../SmartCardReader/libccid/towitoko/README | 14 +
.../Library/SmartCardReader/libccid/towitoko/atr.c | 365 ++++ .../Library/SmartCardReader/libccid/towitoko/atr.h | 111 +
.../SmartCardReader/libccid/towitoko/defines.h | 56 +
.../Library/SmartCardReader/libccid/towitoko/pps.c | 136 ++
.../Library/SmartCardReader/libccid/towitoko/pps.h | 71 +
.../Library/SmartCardReader/libccid/utils.c | 85 +
.../Library/SmartCardReader/libccid/utils.h | 33 +
MdeModulePkg/Library/SmartCardReader/misc.h | 88 +
MdeModulePkg/Library/SmartCardReader/pcsclite.h | 65 +
MdeModulePkg/Library/SmartCardReader/reader.h | 285 +++
MdeModulePkg/Library/SmartCardReader/wintypes.h | 120 +
MdeModulePkg/MdeModulePkg.dsc | 1 +
46 files changed, 12953 insertions(+)
create mode 100644 MdeModulePkg/Library/SmartCardReader/CcidDriver.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/CcidDriver.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/ComponentName.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/ComponentName.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/DriverBinding.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/License.txt
create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader.inf
create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/config.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/debug.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/debuglog.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/ifdhandler.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/commands.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/commands.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/debug.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/debug.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/defs.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/README
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/utils.c
create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/utils.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/misc.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/pcsclite.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/reader.h
create mode 100644 MdeModulePkg/Library/SmartCardReader/wintypes.h

--
2.1.4


------------------------------------------------------------------------------
_______________________________________________
edk2-devel mailing list
edk2-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel
Blibbet
2015-06-11 02:17:19 UTC
Permalink
FAT has a non-BSD license and UEFI Forum found a way to accomodate that
one vendor's legal/licensing issues, and found a separate way for that
to be distributed under Tiano umbrella.

All OS vendors don't hate GPL. Some Linux platforms have non-BSD tools
in use today.

What about a Tiano way to distribute [L]GPL code, safely separate from
main BSD branch, like FAT driver is dealt with, so GPL-friendly
OSVs/ISVs/OEMs -- everyone but Microsoft? :-) -- can safely use GPL
code? Perhaps other non-BSD, OSI-approved FOSS licensed, and no others?

Users of this code will also have to face their main hurdle, getting
Microsoft to bless their EFI code, and their current restrictions
already hinder any GPL code, which gets worse with each Windows release.

There are about 168 UEFI projects on Github today. A few dozen would be
useful to have under Tiano umbrella, current BSD-only licensing issues
would prevent that. A GPL-friendly Tiano subproject would be useful to
gather some code from rEFInd, VirtualBox, and various other Github
projects into one place. Ignoring non-BSD licensed code will continue to
spread UEFI projects in non-Tiano umbrellas and not fix the problem.

On 06/10/2015 06:59 PM, El-Haj-Mahmoud, Samer wrote:
> I agree that the license is an issue. Having GPL or LGPL code in EDK2
risks implementations that use this code. Even if an implementation
choses not to carry this specific driver in binary format, just having
the GPL source in the same tree is a risk. What if developers copy
fragments of code from the GPL licensed driver and use in another module
in the tree that is BSD licensed. Developeers may not pay attention to
the license and its implications since EDK2 so far has used only BSD or
BSD-like license.
>
> -----Original Message-----
> From: Tian, Feng [***@intel.com]
> Received: Wednesday, 10 Jun 2015, 9:52PM
> To: edk2-***@lists.sourceforge.net [edk2-***@lists.sourceforge.net]
> Subject: Re: [edk2] [PATCH 0/4] Add an implementation of
EFI_SMART_CARD_READER_PROTOCOL
>
> Ludovic,
>
> The license issue is the biggest concern. EDKII project is BSD
license, but your proposed patch 1 is using LGPL license which may
corrupt EDKII project.


------------------------------------------------------------------------------
Andrew Fish
2015-06-11 02:41:46 UTC
Permalink
> On Jun 10, 2015, at 7:17 PM, Blibbet <***@gmail.com> wrote:
>
> FAT has a non-BSD license and UEFI Forum found a way to accomodate that
> one vendor's legal/licensing issues, and found a separate way for that
> to be distributed under Tiano umbrella.

The UEFI Forum owns the specifications, not the edk2 open source site. The edk2/Tinao core is an independent open source site. The edk2 is one of many possible implementations of the UEFI Forums specifications.

It is probably confusing due to the overlap of people who are members of the UEFI Forum, and work on the open source site.

>
> All OS vendors don't hate GPL. Some Linux platforms have non-BSD tools
> in use today.
>

BSD is a GPL compatible licence.
GPL is NOT a BSD compatible licence.

> What about a Tiano way to distribute [L]GPL code, safely separate from
> main BSD branch, like FAT driver is dealt with, so GPL-friendly
> OSVs/ISVs/OEMs -- everyone but Microsoft? :-) -- can safely use GPL
> code? Perhaps other non-BSD, OSI-approved FOSS licensed, and no others?
>

As you point out we solve issues with licensing by splitting git repos and having separate projects. That is probably a separate conversation from what goes in the edk2 project.

> Users of this code will also have to face their main hurdle, getting
> Microsoft to bless their EFI code, and their current restrictions
> already hinder any GPL code, which gets worse with each Windows release.
>

I don’t really understand that statement. Microsoft does not “bless” firmware code. The platform vendor can have any firmware implementation they want. There are a set of conformance requirements required to get a discount on the pre-installed Windows, but as far as I know these are mostly quality of implementation tests.

Microsoft also happens to be the CA for UEFI Secure Boot. They have no concern about licensing of the code. They, as a good CA must, care about how secure the code is. The UEFI CA will not sign the UEFI Shell for example, as you could use a script to launch code that is not secure. So yes you can’t write a virus (code the loads unsigned code) and get it signed by the CA. That is exactly how UEFI Secure Boot is supposed to work.

Thanks,

Andrew Fish

> There are about 168 UEFI projects on Github today. A few dozen would be
> useful to have under Tiano umbrella, current BSD-only licensing issues
> would prevent that. A GPL-friendly Tiano subproject would be useful to
> gather some code from rEFInd, VirtualBox, and various other Github
> projects into one place. Ignoring non-BSD licensed code will continue to
> spread UEFI projects in non-Tiano umbrellas and not fix the problem.
>
> On 06/10/2015 06:59 PM, El-Haj-Mahmoud, Samer wrote:
>> I agree that the license is an issue. Having GPL or LGPL code in EDK2
> risks implementations that use this code. Even if an implementation
> choses not to carry this specific driver in binary format, just having
> the GPL source in the same tree is a risk. What if developers copy
> fragments of code from the GPL licensed driver and use in another module
> in the tree that is BSD licensed. Developeers may not pay attention to
> the license and its implications since EDK2 so far has used only BSD or
> BSD-like license.
>>
>> -----Original Message-----
>> From: Tian, Feng [***@intel.com <mailto:***@intel.com>]
>> Received: Wednesday, 10 Jun 2015, 9:52PM
>> To: edk2-***@lists.sourceforge.net <mailto:edk2-***@lists.sourceforge.net> [edk2-***@lists.sourceforge.net <mailto:edk2-***@lists.sourceforge.net>]
>> Subject: Re: [edk2] [PATCH 0/4] Add an implementation of
> EFI_SMART_CARD_READER_PROTOCOL
>>
>> Ludovic,
>>
>> The license issue is the biggest concern. EDKII project is BSD
> license, but your proposed patch 1 is using LGPL license which may
> corrupt EDKII project.
>
>
> ------------------------------------------------------------------------------
> _______________________________________________
> edk2-devel mailing list
> edk2-***@lists.sourceforge.net <mailto:edk2-***@lists.sourceforge.net>
> https://lists.sourceforge.net/lists/listinfo/edk2-devel <https://lists.sourceforge.net/lists/listinfo/edk2-devel>
Blibbet
2015-06-11 13:31:45 UTC
Permalink
> BSD is a GPL compatible licence.
> GPL is NOT a BSD compatible licence.

Where is the requirement that all OEMs must only include BSD code in
their firmware? Why not let Puri.sm or Novena have a downstream UEFI
firmware volume that is GPL, will the world end or something? Today,
there is some non-BSD code needed to boot Linux on UEFI. Linux OSVs
probably don't have the same fear of GPL that closed-source OS vendors
do. You're free to ignore that code and focus on the license subset you
prefer.

>> What about a Tiano way to distribute [L]GPL code, safely separate from
>> main BSD branch, like FAT driver is dealt with, so GPL-friendly
>> OSVs/ISVs/OEMs -- everyone but Microsoft? :-) -- can safely use GPL
>> code? Perhaps other non-BSD, OSI-approved FOSS licensed, and no others?
>>
>
> As you point out we solve issues with licensing by splitting git repos
> and having separate projects. That is probably a separate conversation
> from what goes in the edk2 project.

I thought the conversation was to deal with this current code
contribution, not just focus on EDK2 subproject.

What about using TianoCore's EDK2share for non-BSD projects? That code
isn't bundled into UDK releases. If contributor can relicense to BSD
great, but if not, dropping code is rude, a non-BSD friendly area
outside main EDK2 project, somewhere on Tiano, would be better than
dropping the code, I'd think.

>> Users of this code will also have to face their main hurdle, getting
>> Microsoft to bless their EFI code, and their current restrictions
>> already hinder any GPL code, which gets worse with each Windows release.
>
> I don’t really understand that statement. Microsoft does not “bless”
firmware code.
> The platform vendor can have any firmware implementation they want.

I was referring to 'pre-OS' ISVs. For firmware that doesn't come built
by OEMs/ODMs/IBVs, Microsoft does bless that firmware code, and UEFI
Forum does nothing to help, and Microsoft applies it's own biases and
uses it's position to compete with vendors. I'd at least hope that an
additional techincal and policy restrictions that Microsoft adds to code
would be set by UEFI Forum and not by Microsoft. The Microsoft CA really
is an ugly pink elephant for UEFI Forum, and it helps let them continue
to be a bully in the Intel playground (except in the Apple corner).

And for this case of a smartcard driver, I presume the above Microsoft
comment won't apply since a SC driver has to be (?) bundled into main
FV, not a separate .efi that Microsoft would need to sign.

http://blogs.msdn.com/b/windows_hardware_certification/archive/2013/12/03/microsoft-uefi-ca-signing-policy-updates.aspx
https://msdn.microsoft.com/en-us/library/windows/hardware/dn609883.aspx#reviewprocess
http://techrights.org/2012/06/29/traps-behind-uefi/
http://en.altlinux.org/UEFI_SecureBoot_mini-HOWTO
http://www.itworld.com/article/2737487/it-management/microsoft-washes-its-hands-of-uefi-linux-mess.html

Thanks,
Lee


------------------------------------------------------------------------------
Ludovic Rousseau
2015-06-18 12:55:20 UTC
Permalink
Hello,

How can we progress on the inclusion of my
EFI_SMART_CARD_READER_PROTOCOL proposal in EDK2?

Is the GNU LGPL v2.1+ license really not possible in EDK2 and I should
just forget about integrating my code in EDK2?

The point 5 of Code Contributions [1] says:
"
5. It is preferred that contributions are submitted using the same
copyright license as the base project. When that is not possible,
then contributions using the following licenses can be accepted:
* BSD (2-clause): http://opensource.org/licenses/BSD-2-Clause
* BSD (3-clause): http://opensource.org/licenses/BSD-3-Clause
* MIT: http://opensource.org/licenses/MIT
* Python-2.0: http://opensource.org/licenses/Python-2.0
* Zlib: http://opensource.org/licenses/Zlib

Contributions of code put into the public domain can also be
accepted.

Contributions using other licenses might be accepted, but further
review will be required.
"

It is not clear that GNU LGPL is forbidden.
Do I need to wait that " further review " is made by whoever is in charge?

[1] https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Contributions.txt

2015-06-11 15:31 GMT+02:00 Blibbet <***@gmail.com>:
>> BSD is a GPL compatible licence.
>> GPL is NOT a BSD compatible licence.
>
> Where is the requirement that all OEMs must only include BSD code in
> their firmware? Why not let Puri.sm or Novena have a downstream UEFI
> firmware volume that is GPL, will the world end or something? Today,
> there is some non-BSD code needed to boot Linux on UEFI. Linux OSVs
> probably don't have the same fear of GPL that closed-source OS vendors
> do. You're free to ignore that code and focus on the license subset you
> prefer.
>
>>> What about a Tiano way to distribute [L]GPL code, safely separate from
>>> main BSD branch, like FAT driver is dealt with, so GPL-friendly
>>> OSVs/ISVs/OEMs -- everyone but Microsoft? :-) -- can safely use GPL
>>> code? Perhaps other non-BSD, OSI-approved FOSS licensed, and no others?
>>>
>>
>> As you point out we solve issues with licensing by splitting git repos
>> and having separate projects. That is probably a separate conversation
>> from what goes in the edk2 project.
>
> I thought the conversation was to deal with this current code
> contribution, not just focus on EDK2 subproject.
>
> What about using TianoCore's EDK2share for non-BSD projects? That code
> isn't bundled into UDK releases. If contributor can relicense to BSD
> great, but if not, dropping code is rude, a non-BSD friendly area
> outside main EDK2 project, somewhere on Tiano, would be better than
> dropping the code, I'd think.

I am not familiar with EDK2share.
Hosting "non-free-enough" source code in a EDK2 side project could
also be a possibility.

My code is available in the SmartCard branch or my edk2 fork at
https://github.com/LudovicRousseau/edk2/tree/SmartCard
But is it not really easy to find and use.

Regards,

--
Dr. Ludovic Rousseau

------------------------------------------------------------------------------
Tian, Feng
2015-06-19 01:28:27 UTC
Permalink
Hi, Ludovic

Just like I said before, license issue is the biggest concern. Our license expert has confirmed GNU LGPL license would corrupt EDKII BSD license. So I would suggest you wait till we have clear conclusion on how to handle non-BSD license.

As for should TianoCore/EDKII be extended to support other licenses, I would suggest you resend another mail to discuss it specifically. By this way, more people could be involved (many people may ignore the discussion as the mail title has no business with license issue from literal.)

Thanks
Feng

-----Original Message-----
From: Ludovic Rousseau [mailto:***@gmail.com]
Sent: Thursday, June 18, 2015 20:55
To: edk2-***@lists.sourceforge.net
Subject: Re: [edk2] [PATCH 0/4] Add an implementation of EFI_SMART_CARD_READER_PROTOCOL

Hello,

How can we progress on the inclusion of my EFI_SMART_CARD_READER_PROTOCOL proposal in EDK2?

Is the GNU LGPL v2.1+ license really not possible in EDK2 and I should just forget about integrating my code in EDK2?

The point 5 of Code Contributions [1] says:
"
5. It is preferred that contributions are submitted using the same
copyright license as the base project. When that is not possible,
then contributions using the following licenses can be accepted:
* BSD (2-clause): http://opensource.org/licenses/BSD-2-Clause
* BSD (3-clause): http://opensource.org/licenses/BSD-3-Clause
* MIT: http://opensource.org/licenses/MIT
* Python-2.0: http://opensource.org/licenses/Python-2.0
* Zlib: http://opensource.org/licenses/Zlib

Contributions of code put into the public domain can also be
accepted.

Contributions using other licenses might be accepted, but further
review will be required.
"

It is not clear that GNU LGPL is forbidden.
Do I need to wait that " further review " is made by whoever is in charge?

[1] https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Contributions.txt

2015-06-11 15:31 GMT+02:00 Blibbet <***@gmail.com>:
>> BSD is a GPL compatible licence.
>> GPL is NOT a BSD compatible licence.
>
> Where is the requirement that all OEMs must only include BSD code in
> their firmware? Why not let Puri.sm or Novena have a downstream UEFI
> firmware volume that is GPL, will the world end or something? Today,
> there is some non-BSD code needed to boot Linux on UEFI. Linux OSVs
> probably don't have the same fear of GPL that closed-source OS vendors
> do. You're free to ignore that code and focus on the license subset
> you prefer.
>
>>> What about a Tiano way to distribute [L]GPL code, safely separate
>>> from main BSD branch, like FAT driver is dealt with, so GPL-friendly
>>> OSVs/ISVs/OEMs -- everyone but Microsoft? :-) -- can safely use GPL
>>> code? Perhaps other non-BSD, OSI-approved FOSS licensed, and no others?
>>>
>>
>> As you point out we solve issues with licensing by splitting git
>> repos and having separate projects. That is probably a separate
>> conversation from what goes in the edk2 project.
>
> I thought the conversation was to deal with this current code
> contribution, not just focus on EDK2 subproject.
>
> What about using TianoCore's EDK2share for non-BSD projects? That code
> isn't bundled into UDK releases. If contributor can relicense to BSD
> great, but if not, dropping code is rude, a non-BSD friendly area
> outside main EDK2 project, somewhere on Tiano, would be better than
> dropping the code, I'd think.

I am not familiar with EDK2share.
Hosting "non-free-enough" source code in a EDK2 side project could also be a possibility.

My code is available in the SmartCard branch or my edk2 fork at https://github.com/LudovicRousseau/edk2/tree/SmartCard
But is it not really easy to find and use.

Regards,

--
Dr. Ludovic Rousseau
Ludovic Rousseau
2015-06-11 08:48:44 UTC
Permalink
Hello,

2015-06-11 3:59 GMT+02:00 El-Haj-Mahmoud, Samer <samer.el-haj-***@hp.com>:
> I agree that the license is an issue. Having GPL or LGPL code in EDK2 risks implementations that use this code. Even if an implementation choses not to carry this specific driver in binary format, just having the GPL source in the same tree is a risk. What if developers copy fragments of code from the GPL licensed driver and use in another module in the tree that is BSD licensed. Developeers may not pay attention to the license and its implications since EDK2 so far has used only BSD or BSD-like license.

I am not surprise to get some opposition because of the license.
Note that the license is LGPL (Lesser GPL) version 2.1 and not Lesser
GPL version 3 or GPL (I think GPL license would not be accepted in
edk2).

It is a political question. Should edk2 accept non BSD licenses?
Maybe such code can be stored in a "non-BSD/" (or another more
explicit name) sub hierarchy in edk2 to clearly indicates the license
difference?

I will help the edk2 project as much as I can with this integration.

Regards,

> -----Original Message-----
> From: Tian, Feng [***@intel.com]
> Received: Wednesday, 10 Jun 2015, 9:52PM
> To: edk2-***@lists.sourceforge.net [edk2-***@lists.sourceforge.net]
> Subject: Re: [edk2] [PATCH 0/4] Add an implementation of EFI_SMART_CARD_READER_PROTOCOL
>
> Ludovic,
>
> The license issue is the biggest concern. EDKII project is BSD license, but your proposed patch 1 is using LGPL license which may corrupt EDKII project.
>
> Thanks
> Feng
>
> -----Original Message-----
> From: Ludovic Rousseau [mailto:***@gmail.com]
> Sent: Thursday, June 11, 2015 02:28
> To: edk2-***@lists.sourceforge.net
> Cc: Ludovic Rousseau
> Subject: [edk2] [PATCH 0/4] Add an implementation of EFI_SMART_CARD_READER_PROTOCOL
>
> This patch serie provides an implementation for the EFI_SMART_CARD_READER_PROTOCOL added in UEFI version 2.5.
>
> It is a port of my CCID driver from Unix to UEFI. Only part of the code has been specifically written for UEFI and edk2. Only this part of the code follows the coding rules. The idea os to keep most of the code common to edk2 and my original CCID driver so code is easy to backport from one project to the other.
>
> patch 1: are files from the libccid project [1], GNU LGLP v2.1 patch 2: are files from the pcsc-lite project [2], TianoCore Contribution Agreement 1.0 patch 3: are files specifically written for edk2, TianoCore Contribution Agreement 1.0 patch 4: edit MdeModulePkg/MdeModulePkg.dsc to add the driver, TianoCore Contribution Agreement 1.0
>
> The code has been tested on a Dell E6430 with an internal Broadcom smart card reader and also different external USB smart card readers.
>
> [1] https://pcsclite.alioth.debian.org/ccid.html
> [2] https://pcsclite.alioth.debian.org/pcsclite.html
>
>
> Ludovic Rousseau (4):
> MdeModulePkg/SmartCardReader: Add files from the libccid project
> MdeModulePkg/SmartCardReader: Add files from pcsc-lite project
> MdeModulePkg/SmartCardReader: Implement Smart Card Reader Protocol
> MdeModulePkg: add SmartCardReader.inf
>
> MdeModulePkg/Library/SmartCardReader/CcidDriver.c | 819 +++++++ MdeModulePkg/Library/SmartCardReader/CcidDriver.h | 154 ++
> .../Library/SmartCardReader/ComponentName.c | 198 ++
> .../Library/SmartCardReader/ComponentName.h | 128 ++
> .../Library/SmartCardReader/DriverBinding.h | 211 ++
> MdeModulePkg/Library/SmartCardReader/License.txt | 87 +
> .../Library/SmartCardReader/SmartCardReader.inf | 97 +
> .../Library/SmartCardReader/SmartCardReader_impl.c | 453 ++++
> .../Library/SmartCardReader/SmartCardReader_impl.h | 94 +
> MdeModulePkg/Library/SmartCardReader/config.h | 64 +
> MdeModulePkg/Library/SmartCardReader/debug.c | 62 +
> MdeModulePkg/Library/SmartCardReader/debuglog.h | 81 +
> MdeModulePkg/Library/SmartCardReader/ifdhandler.h | 825 +++++++
> .../Library/SmartCardReader/libccid/ccid.c | 659 ++++++
> .../Library/SmartCardReader/libccid/ccid.h | 340 +++
> .../SmartCardReader/libccid/ccid_ifdhandler.h | 63 +
> .../Library/SmartCardReader/libccid/ccid_uefi.c | 470 ++++
> .../Library/SmartCardReader/libccid/ccid_uefi.h | 46 +
> .../Library/SmartCardReader/libccid/commands.c | 2294 ++++++++++++++++++++
> .../Library/SmartCardReader/libccid/commands.h | 64 +
> .../Library/SmartCardReader/libccid/debug.c | 157 ++
> .../Library/SmartCardReader/libccid/debug.h | 100 +
> .../Library/SmartCardReader/libccid/defs.h | 126 ++
> .../Library/SmartCardReader/libccid/ifdhandler.c | 2265 +++++++++++++++++++
> .../Library/SmartCardReader/libccid/openct/LICENSE | 28 +
> .../Library/SmartCardReader/libccid/openct/README | 7 +
> .../SmartCardReader/libccid/openct/buffer.c | 73 +
> .../SmartCardReader/libccid/openct/buffer.h | 36 +
> .../SmartCardReader/libccid/openct/checksum.c | 95 +
> .../SmartCardReader/libccid/openct/checksum.h | 37 +
> .../SmartCardReader/libccid/openct/proto-t1.c | 800 +++++++
> .../SmartCardReader/libccid/openct/proto-t1.h | 85 +
> .../SmartCardReader/libccid/towitoko/COPYING | 505 +++++
> .../SmartCardReader/libccid/towitoko/README | 14 +
> .../Library/SmartCardReader/libccid/towitoko/atr.c | 365 ++++ .../Library/SmartCardReader/libccid/towitoko/atr.h | 111 +
> .../SmartCardReader/libccid/towitoko/defines.h | 56 +
> .../Library/SmartCardReader/libccid/towitoko/pps.c | 136 ++
> .../Library/SmartCardReader/libccid/towitoko/pps.h | 71 +
> .../Library/SmartCardReader/libccid/utils.c | 85 +
> .../Library/SmartCardReader/libccid/utils.h | 33 +
> MdeModulePkg/Library/SmartCardReader/misc.h | 88 +
> MdeModulePkg/Library/SmartCardReader/pcsclite.h | 65 +
> MdeModulePkg/Library/SmartCardReader/reader.h | 285 +++
> MdeModulePkg/Library/SmartCardReader/wintypes.h | 120 +
> MdeModulePkg/MdeModulePkg.dsc | 1 +
> 46 files changed, 12953 insertions(+)
> create mode 100644 MdeModulePkg/Library/SmartCardReader/CcidDriver.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/CcidDriver.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/ComponentName.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/ComponentName.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/DriverBinding.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/License.txt
> create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader.inf
> create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/SmartCardReader_impl.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/config.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/debug.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/debuglog.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/ifdhandler.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_ifdhandler.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ccid_uefi.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/commands.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/commands.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/debug.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/debug.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/defs.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/ifdhandler.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/LICENSE
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/README
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/buffer.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/checksum.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/openct/proto-t1.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/COPYING
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/README
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/atr.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/defines.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/towitoko/pps.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/utils.c
> create mode 100644 MdeModulePkg/Library/SmartCardReader/libccid/utils.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/misc.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/pcsclite.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/reader.h
> create mode 100644 MdeModulePkg/Library/SmartCardReader/wintypes.h
>
> --
> 2.1.4
>
>
> ------------------------------------------------------------------------------
> _______________________________________________
> edk2-devel mailing list
> edk2-***@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/edk2-devel
>
> ------------------------------------------------------------------------------
> _______________________________________________
> edk2-devel mailing list
> edk2-***@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/edk2-devel
>
> ------------------------------------------------------------------------------
> _______________________________________________
> edk2-devel mailing list
> edk2-***@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/edk2-devel



--
Dr. Ludovic Rousseau

------------------------------------------------------------------------------
Loading...