diff --git a/repos/libports/lib/import/import-pcsc-lite.mk b/repos/libports/lib/import/import-pcsc-lite.mk
new file mode 100644
index 000000000..63fadc823
--- /dev/null
+++ b/repos/libports/lib/import/import-pcsc-lite.mk
@@ -0,0 +1 @@
+INC_DIR += $(call select_from_ports,pcsc-lite)/include/PCSC
diff --git a/repos/libports/lib/mk/pcsc-lite.mk b/repos/libports/lib/mk/pcsc-lite.mk
new file mode 100644
index 000000000..3dea4e724
--- /dev/null
+++ b/repos/libports/lib/mk/pcsc-lite.mk
@@ -0,0 +1,51 @@
+PCSC_LITE_DIR := $(call select_from_ports,pcsc-lite)/src/lib/pcsc-lite
+
+include $(call select_from_repositories,lib/import/import-pcsc-lite.mk)
+
+LIBS += ccid libc
+
+# find 'config.h'
+INC_DIR += $(REP_DIR)/src/lib/pcsc-lite
+
+INC_DIR += $(PCSC_LITE_DIR)/src
+
+CC_DEF += -DPCSCLITE_STATIC_DRIVER -DIFDHANDLERv3 -DGENODE
+
+SRC_C = debug.c \
+ error.c \
+ winscard_clnt.c \
+ simclist.c \
+ sys_unix.c \
+ utils.c \
+ winscard_msg.c \
+ auth.c \
+ atrhandler.c \
+ debuglog.c \
+ dyn_unix.c \
+ eventhandler.c \
+ hotplug_generic.c \
+ ifdwrapper.c \
+ powermgt_generic.c \
+ prothandler.c \
+ readerfactory.c \
+ winscard.c
+
+SRC_CC = init.cc
+
+CC_OPT_winscard = -DSCardEstablishContext=SCardEstablishContextImpl \
+ -DSCardReleaseContext=SCardReleaseContextImpl \
+ -DSCardConnect=SCardConnectImpl \
+ -DSCardReconnect=SCardReconnectImpl \
+ -DSCardDisconnect=SCardDisconnectImpl \
+ -DSCardBeginTransaction=SCardBeginTransactionImpl \
+ -DSCardEndTransaction=SCardEndTransactionImpl \
+ -DSCardStatus=SCardStatusImpl \
+ -DSCardControl=SCardControlImpl \
+ -DSCardGetAttrib=SCardGetAttribImpl \
+ -DSCardSetAttrib=SCardSetAttribImpl \
+ -DSCardTransmit=SCardTransmitImpl
+
+vpath %.c $(PCSC_LITE_DIR)/src
+vpath %.cc $(REP_DIR)/src/lib/pcsc-lite
+
+SHARED_LIB = yes
diff --git a/repos/libports/ports/pcsc-lite.hash b/repos/libports/ports/pcsc-lite.hash
new file mode 100644
index 000000000..9f6ce4e74
--- /dev/null
+++ b/repos/libports/ports/pcsc-lite.hash
@@ -0,0 +1 @@
+e32624a4145b75f8a2aebe55418fa2fb510faf4b
diff --git a/repos/libports/ports/pcsc-lite.port b/repos/libports/ports/pcsc-lite.port
new file mode 100644
index 000000000..2122387c0
--- /dev/null
+++ b/repos/libports/ports/pcsc-lite.port
@@ -0,0 +1,13 @@
+LICENSE := LGPL
+DOWNLOADS := pcsc-lite.archive
+VERSION := 1.8.18
+
+URL(pcsc-lite) := https://alioth.debian.org/frs/download.php/file/4179/pcsc-lite-$(VERSION).tar.bz2
+SHA(pcsc-lite) := 2a2552f7196457f5750efad1b29affd0a9620890
+DIR(pcsc-lite) := src/lib/pcsc-lite
+
+DIRS := include/PCSC
+DIR_CONTENT(include/PCSC) := $(addprefix src/lib/pcsc-lite/src/PCSC/,debuglog.h ifdhandler.h pcsclite.h reader.h winscard.h wintypes.h)
+
+PATCHES := src/lib/pcsc-lite/pcsc-lite.patch
+PATCH_OPT := -p1 -d src/lib/pcsc-lite
diff --git a/repos/libports/run/smartcard.run b/repos/libports/run/smartcard.run
new file mode 100644
index 000000000..1e456f3ce
--- /dev/null
+++ b/repos/libports/run/smartcard.run
@@ -0,0 +1,124 @@
+#
+# Smartcard test
+#
+# NOTE: The vendor id and product id of the USB card reader to be used must be
+# configured for the application and for the USB driver.
+#
+
+if { [have_include "power_on/qemu"] || [have_spec linux] } {
+ puts "Run script does not support Qemu or Linux"
+ exit 0
+}
+
+if { [get_cmd_switch --autopilot] && ![have_spec x86] } {
+ puts "Run script is only supported in autopilot mode on x86 platforms"
+ exit 0
+}
+
+#
+# Build
+#
+
+set build_components {
+ core init
+ drivers/timer
+ drivers/usb
+ test/smartcard
+}
+
+lappend_if [have_spec gpio] build_components drivers/gpio
+
+source ${genode_dir}/repos/base/run/platform_drv.inc
+append_platform_drv_build_components
+
+build $build_components
+
+create_boot_directory
+
+#
+# Generate config
+#
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_if [have_spec gpio] config {
+
+
+
+
+ }
+
+append_platform_drv_config
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+#
+# Boot modules
+#
+
+# generic modules
+set boot_modules {
+ core init timer usb_drv test-smartcard
+ ld.lib.so pcsc-lite.lib.so ccid.lib.so libusb.lib.so
+ libc.lib.so libc_pipe.lib.so pthread.lib.so
+ Info.plist
+}
+
+lappend_if [have_spec gpio] boot_modules gpio_drv
+
+append_platform_drv_boot_modules
+
+build_boot_image $boot_modules
+
+run_genode_until { Response: 62 0A 82 01 38 83 02 3F 00 8A 01 05 90 00} 30
+
+exec rm bin/Info.plist
diff --git a/repos/libports/src/lib/pcsc-lite/README b/repos/libports/src/lib/pcsc-lite/README
new file mode 100644
index 000000000..192f43826
--- /dev/null
+++ b/repos/libports/src/lib/pcsc-lite/README
@@ -0,0 +1,12 @@
+The USB card reader to be used by an application must be configured with its
+vendor id and product id in a file '/config.pcsc-lite':
+
+
+
+
+
+
+
+
+
+
diff --git a/repos/libports/src/lib/pcsc-lite/config.h b/repos/libports/src/lib/pcsc-lite/config.h
new file mode 100644
index 000000000..cb524e3fa
--- /dev/null
+++ b/repos/libports/src/lib/pcsc-lite/config.h
@@ -0,0 +1,245 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* display ATR parsing debug messages. */
+/* #undef ATR_DEBUG */
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define to 1 if using `alloca.c'. */
+/* #undef C_ALLOCA */
+
+/* Filter reader names */
+/* #undef FILTER_NAMES */
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+/* undef HAVE_ALLOCA */
+
+/* Define to 1 if you have and it should be used (not on Ultrix).
+ */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define to 1 if you have the header file, and it defines `DIR'.
+ */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_DL_H */
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Libudev is available */
+/* #undef HAVE_LIBUDEV */
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_LIBUDEV_H */
+
+/* Libusb is available */
+/* #undef HAVE_LIBUSB */
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_LIBUSB_H */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `nanosleep' function. */
+#define HAVE_NANOSLEEP 1
+
+/* Define to 1 if you have the header file, and it defines `DIR'. */
+/* #undef HAVE_NDIR_H */
+
+/* Build polkit access control support */
+/* #undef HAVE_POLKIT */
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD 1
+
+/* Define to 1 if you have the `pthread_cancel' function. */
+#define HAVE_PTHREAD_CANCEL 1
+
+/* Have PTHREAD_PRIO_INHERIT. */
+#define HAVE_PTHREAD_PRIO_INHERIT 1
+
+/* Define to 1 if `stat' has the bug that it succeeds when given the
+ zero-length file name argument. */
+/* #undef HAVE_STAT_EMPTY_STRING_BUG */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if `d_type' is a member of `struct dirent'. */
+#define HAVE_STRUCT_DIRENT_D_TYPE 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define to 1 if you have the header file. */
+/* #undef HAVE_SYS_FILIO_H */
+
+/* Define to 1 if you have the header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Disable logging support */
+/* #undef NO_LOG */
+
+/* Name of package */
+#define PACKAGE "pcsc-lite"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "pcsc-lite"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "pcsc-lite 1.8.18"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "pcsc-lite"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.8.18"
+
+/* pcscd filename */
+#define PCSCD_BINARY "/usr/local/sbin/pcscd"
+
+/* Enabled PC/SC lite features */
+#define PCSCLITE_FEATURES " Linux x86_64-pc-linux-gnu usbdropdir=/ ipcdir=/var/run/pcscd configdir=/usr/local/etc/reader.conf.d"
+
+/* directory containing USB drivers */
+#define PCSCLITE_HP_DROPDIR "/"
+
+/* PC/SC target architecture */
+#define PCSC_ARCH "Linux"
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at runtime.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+/* #undef STACK_DIRECTION */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both and . */
+#define TIME_WITH_SYS_TIME 1
+
+/* directory containing IPC files */
+#define USE_IPCDIR "/var/run/pcscd"
+
+/* Use serial conf file mechanism */
+/* #undef USE_SERIAL */
+
+/* Use USB hotplug mechanism */
+/* #undef USE_USB */
+
+/* Version number of package */
+#define VERSION "1.8.18"
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* # undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#define YYTEXT_POINTER 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `int' if doesn't define. */
+/* #undef gid_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if does not define. */
+/* #undef size_t */
+
+/* Define to `int' if doesn't define. */
+/* #undef uid_t */
diff --git a/repos/libports/src/lib/pcsc-lite/init.cc b/repos/libports/src/lib/pcsc-lite/init.cc
new file mode 100644
index 000000000..214b0d3f8
--- /dev/null
+++ b/repos/libports/src/lib/pcsc-lite/init.cc
@@ -0,0 +1,88 @@
+/*
+ * \brief pcsc-lite initialization
+ * \author Christian Prochaska
+ * \date 2016-10-11
+ */
+
+/*
+ * Copyright (C) 2016 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* libc includes */
+#include
+#include
+#include
+#include
+
+/* pcsc-lite includes */
+extern "C" {
+#include
+#include
+}
+
+static constexpr bool verbose = false;
+
+struct Pcsc_lite_initializer
+{
+ Pcsc_lite_initializer()
+ {
+ if (verbose) {
+ /* pcscd -f */
+ DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
+ /* pcscd -d */
+ DebugLogSetLevel(PCSC_LOG_DEBUG);
+ /* pcscd -a */
+ (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
+ }
+
+ unsigned int vendor_id = 0x0000;
+ unsigned int product_id = 0x0000;
+
+ int fd = open("/config.pcsc-lite", O_RDONLY);
+
+ if (fd < 0) {
+ Genode::error("Could not open 'config.pcsc-lite'");
+ exit(1);
+ }
+
+ char config[128];
+ if (read(fd, config, sizeof(config)) < 0) {
+ Genode::error("Could not read 'config.pcsc-lite'");
+ exit(1);
+ }
+
+ try {
+
+ Genode::Xml_node config_node(config);
+
+ vendor_id = config_node.attribute_value("vendor_id", 0U);
+ product_id = config_node.attribute_value("product_id", 0U);
+
+ } catch (...) {
+ Genode::error("Error parsing 'config.pcsc-lite'");
+ exit(1);
+ }
+
+ close(fd);
+
+ char device[14];
+
+ snprintf(device, sizeof(device), "usb:%04x/%04x", vendor_id, product_id);
+
+ RFAllocateReaderSpace(0);
+ (void)RFAddReader("CCID", 0, "/", device);
+ }
+};
+
+
+extern "C" void initialize_pcsc_lite()
+{
+ static Pcsc_lite_initializer pcsc_lite_initializer;
+}
diff --git a/repos/libports/src/lib/pcsc-lite/pcsc-lite.patch b/repos/libports/src/lib/pcsc-lite/pcsc-lite.patch
new file mode 100644
index 000000000..252e90ed0
--- /dev/null
+++ b/repos/libports/src/lib/pcsc-lite/pcsc-lite.patch
@@ -0,0 +1,760 @@
+pcsc-lite.patch
+
+From: Christian Prochaska
+
+
+---
+ src/debug.c | 3
+ src/readerfactory.c | 2
+ src/winscard_clnt.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 374 insertions(+), 8 deletions(-)
+
+diff --git a/src/debug.c b/src/debug.c
+index d2fb5bf..1f6bccc 100644
+--- a/src/debug.c
++++ b/src/debug.c
+@@ -101,6 +101,7 @@ static void log_init(void)
+ }
+ } /* log_init */
+
++#ifndef GENODE
+ void log_msg(const int priority, const char *fmt, ...)
+ {
+ char DebugBuffer[DEBUG_BUF_SIZE];
+@@ -150,6 +151,6 @@ void log_msg(const int priority, const char *fmt, ...)
+ fprintf(stderr, "%s\n", DebugBuffer);
+ }
+ } /* log_msg */
+-
++#endif
+ #endif
+
+diff --git a/src/readerfactory.c b/src/readerfactory.c
+index 4f97892..3bec158 100644
+--- a/src/readerfactory.c
++++ b/src/readerfactory.c
+@@ -1399,7 +1399,7 @@ void RFCleanupReaders(void)
+ * Wait until all connected readers have a chance to power up a possibly
+ * inserted card.
+ */
+-#ifdef USE_USB
++#if defined(USE_USB) || defined(GENODE)
+ void RFWaitForReaderInit(void)
+ {
+ int i, need_to_wait;
+diff --git a/src/winscard_clnt.c b/src/winscard_clnt.c
+index 94d4cf5..bf18c7c 100644
+--- a/src/winscard_clnt.c
++++ b/src/winscard_clnt.c
+@@ -113,6 +113,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ #include
+ #include
+ #include
++#include
+
+ #include "misc.h"
+ #include "pcscd.h"
+@@ -143,6 +144,52 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ static char sharing_shall_block = TRUE;
+
++#ifdef GENODE
++
++static int event_pipe[2];
++
++extern void initialize_pcsc_lite();
++
++LONG MSGSignalClient(uint32_t filedes, LONG rv)
++{
++ ssize_t bytes_written = write(filedes, &rv, sizeof(rv));
++
++ if (bytes_written == sizeof(rv))
++ return SCARD_S_SUCCESS;
++ else
++ return SCARD_F_UNKNOWN_ERROR;
++}
++
++extern LONG SCardEstablishContextImpl(DWORD dwScope, LPCVOID pvReserved1,
++ LPCVOID pvReserved2,
++ LPSCARDCONTEXT phContext);
++extern LONG SCardReleaseContextImpl(SCARDCONTEXT hContext);
++extern LONG SCardConnectImpl(SCARDCONTEXT hContext, LPCSTR szReader,
++ DWORD dwShareMode, DWORD dwPreferredProtocols,
++ LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol);
++extern LONG SCardReconnectImpl(SCARDHANDLE hCard, DWORD dwShareMode,
++ DWORD dwPreferredProtocols, DWORD dwInitialization,
++ LPDWORD pdwActiveProtocol);
++extern LONG SCardDisconnectImpl(SCARDHANDLE hCard, DWORD dwDisposition);
++extern LONG SCardBeginTransactionImpl(SCARDHANDLE hCard);
++extern LONG SCardEndTransactionImpl(SCARDHANDLE hCard, DWORD dwDisposition);
++extern LONG SCardStatusImpl(SCARDHANDLE hCard, LPSTR szReaderNames,
++ LPDWORD pcchReaderLen, LPDWORD pdwState,
++ LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen);
++extern LONG SCardControlImpl(SCARDHANDLE hCard, DWORD dwControlCode,
++ LPCVOID pbSendBuffer, DWORD cbSendLength,
++ LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned);
++extern LONG SCardGetAttribImpl(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
++ LPDWORD pcbAttrLen);
++extern LONG SCardSetAttribImpl(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
++ DWORD cbAttrLen);
++extern LONG SCardTransmitImpl(SCARDHANDLE hCard,
++ const SCARD_IO_REQUEST *pioSendPci,
++ LPCBYTE pbSendBuffer, DWORD cbSendLength,
++ SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
++ LPDWORD pcbRecvLength);
++#endif
++
+ #define COLOR_RED "\33[01;31m"
+ #define COLOR_GREEN "\33[32m"
+ #define COLOR_BLUE "\33[34m"
+@@ -355,7 +402,11 @@ static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
+ /**
+ * Area used to read status information about the readers.
+ */
++#ifndef GENODE
+ static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
++#else
++extern READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
++#endif
+
+ /** Protocol Control Information for T=0 */
+ PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(SCARD_IO_REQUEST) };
+@@ -451,17 +502,22 @@ LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
+ API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
+ PROFILE_START
+
++#ifndef GENODE
+ /* Check if the server is running */
+ rv = SCardCheckDaemonAvailability();
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
++#endif
+
+ (void)SCardLockThread();
+ rv = SCardEstablishContextTH(dwScope, pvReserved1,
+ pvReserved2, phContext);
+ (void)SCardUnlockThread();
+
++#ifndef GENODE
+ end:
++#endif
++
+ PROFILE_END(rv)
+ API_TRACE_OUT("%ld", *phContext)
+
+@@ -548,7 +604,7 @@ static LONG SCardEstablishContextTH(DWORD dwScope,
+ isExecuted = 1;
+ }
+
+-
++#ifndef GENODE
+ /* Establishes a connection to the server */
+ if (ClientSetupSession(&dwClientID) != 0)
+ {
+@@ -582,6 +638,17 @@ static LONG SCardEstablishContextTH(DWORD dwScope,
+ if (veStr.rv != SCARD_S_SUCCESS)
+ return veStr.rv;
+ }
++#else
++
++ initialize_pcsc_lite();
++
++ rv = pipe(event_pipe);
++ if (rv < 0) {
++ fprintf(stderr, "Could not create pipe\n");
++ return rv;
++ }
++
++#endif
+
+ again:
+ /*
+@@ -591,6 +658,7 @@ again:
+ scEstablishStruct.hContext = 0;
+ scEstablishStruct.rv = SCARD_S_SUCCESS;
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(SCARD_ESTABLISH_CONTEXT, dwClientID,
+ sizeof(scEstablishStruct), (void *) &scEstablishStruct);
+
+@@ -605,6 +673,21 @@ again:
+
+ if (rv != SCARD_S_SUCCESS)
+ return rv;
++#else
++
++ struct establish_struct esStr;
++ SCARDCONTEXT hContext;
++
++ esStr = scEstablishStruct;
++
++ hContext = esStr.hContext;
++ esStr.rv = SCardEstablishContextImpl(esStr.dwScope, 0, 0,
++ &hContext);
++ esStr.hContext = hContext;
++
++ scEstablishStruct = esStr;
++
++#endif
+
+ if (scEstablishStruct.rv != SCARD_S_SUCCESS)
+ return scEstablishStruct.rv;
+@@ -669,6 +752,7 @@ LONG SCardReleaseContext(SCARDCONTEXT hContext)
+ scReleaseStruct.hContext = hContext;
+ scReleaseStruct.rv = SCARD_S_SUCCESS;
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(SCARD_RELEASE_CONTEXT,
+ currentContextMap->dwClientID,
+ sizeof(scReleaseStruct), (void *) &scReleaseStruct);
+@@ -684,9 +768,23 @@ LONG SCardReleaseContext(SCARDCONTEXT hContext)
+
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
++#else
++
++ struct release_struct reStr;
++
++ reStr = scReleaseStruct;
++
++ reStr.rv = SCardReleaseContextImpl(reStr.hContext);
++
++ scReleaseStruct = reStr;
++
++#endif
+
+ rv = scReleaseStruct.rv;
++
++#ifndef GENODE
+ end:
++#endif
+ (void)pthread_mutex_unlock(¤tContextMap->mMutex);
+
+ /*
+@@ -805,6 +903,8 @@ LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
+ scConnectStruct.dwActiveProtocol = 0;
+ scConnectStruct.rv = SCARD_S_SUCCESS;
+
++#ifndef GENODE
++
+ rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
+ sizeof(scConnectStruct), (void *) &scConnectStruct);
+
+@@ -820,6 +920,29 @@ LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
+
++#else
++
++ struct connect_struct coStr;
++ SCARDHANDLE hCard;
++ DWORD dwActiveProtocol;
++
++ coStr = scConnectStruct;
++
++ coStr.szReader[sizeof(coStr.szReader)-1] = 0;
++ hCard = coStr.hCard;
++ dwActiveProtocol = coStr.dwActiveProtocol;
++
++ coStr.rv = SCardConnectImpl(coStr.hContext, coStr.szReader,
++ coStr.dwShareMode, coStr.dwPreferredProtocols,
++ &hCard, &dwActiveProtocol);
++
++ coStr.hCard = hCard;
++ coStr.dwActiveProtocol = dwActiveProtocol;
++
++ scConnectStruct = coStr;
++
++#endif
++
+ *phCard = scConnectStruct.hCard;
+ *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
+
+@@ -833,7 +956,10 @@ LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
+ else
+ rv = scConnectStruct.rv;
+
++#ifndef GENODE
+ end:
++#endif
++
+ (void)pthread_mutex_unlock(¤tContextMap->mMutex);
+
+ PROFILE_END(rv)
+@@ -948,6 +1074,7 @@ retry:
+ scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
+ scReconnectStruct.rv = SCARD_S_SUCCESS;
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
+ sizeof(scReconnectStruct), (void *) &scReconnectStruct);
+
+@@ -962,6 +1089,21 @@ retry:
+
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
++#else
++
++ struct reconnect_struct rcStr;
++ DWORD dwActiveProtocol;
++
++ rcStr = scReconnectStruct;
++
++ rcStr.rv = SCardReconnectImpl(rcStr.hCard, rcStr.dwShareMode,
++ rcStr.dwPreferredProtocols, rcStr.dwInitialization,
++ &dwActiveProtocol);
++ rcStr.dwActiveProtocol = dwActiveProtocol;
++
++ scReconnectStruct = rcStr;
++
++#endif
+
+ rv = scReconnectStruct.rv;
+
+@@ -974,7 +1116,9 @@ retry:
+
+ *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
+
++#ifndef GENODE
+ end:
++#endif
+ (void)pthread_mutex_unlock(¤tContextMap->mMutex);
+
+ PROFILE_END(rv)
+@@ -1039,6 +1183,7 @@ LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
+ scDisconnectStruct.dwDisposition = dwDisposition;
+ scDisconnectStruct.rv = SCARD_S_SUCCESS;
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
+ sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
+
+@@ -1053,12 +1198,25 @@ LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
+
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
++#else
++
++ struct disconnect_struct diStr;
++
++ diStr = scDisconnectStruct;
++
++ diStr.rv = SCardDisconnectImpl(diStr.hCard, diStr.dwDisposition);
++
++ scDisconnectStruct = diStr;
++
++#endif
+
+ if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
+ (void)SCardRemoveHandle(hCard);
+ rv = scDisconnectStruct.rv;
+
++#ifndef GENODE
+ end:
++#endif
+ (void)pthread_mutex_unlock(¤tContextMap->mMutex);
+
+ error:
+@@ -1132,6 +1290,7 @@ LONG SCardBeginTransaction(SCARDHANDLE hCard)
+ scBeginStruct.hCard = hCard;
+ scBeginStruct.rv = SCARD_S_SUCCESS;
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(SCARD_BEGIN_TRANSACTION,
+ currentContextMap->dwClientID,
+ sizeof(scBeginStruct), (void *) &scBeginStruct);
+@@ -1147,6 +1306,17 @@ LONG SCardBeginTransaction(SCARDHANDLE hCard)
+
+ if (rv != SCARD_S_SUCCESS)
+ break;
++#else
++
++ struct begin_struct beStr;
++
++ beStr = scBeginStruct;
++
++ beStr.rv = SCardBeginTransactionImpl(beStr.hCard);
++
++ scBeginStruct = beStr;
++
++#endif
+
+ rv = scBeginStruct.rv;
+
+@@ -1227,6 +1397,7 @@ LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
+ scEndStruct.dwDisposition = dwDisposition;
+ scEndStruct.rv = SCARD_S_SUCCESS;
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(SCARD_END_TRANSACTION,
+ currentContextMap->dwClientID,
+ sizeof(scEndStruct), (void *) &scEndStruct);
+@@ -1242,6 +1413,18 @@ LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
+
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
++#else
++
++ struct end_struct enStr;
++
++ enStr = scEndStruct;
++
++ enStr.rv = SCardEndTransactionImpl(enStr.hCard,
++ enStr.dwDisposition);
++
++ scEndStruct = enStr;
++
++#endif
+
+ /*
+ * This helps prevent starvation
+@@ -1250,7 +1433,9 @@ LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
+ (void)SYS_USleep(randnum);
+ rv = scEndStruct.rv;
+
++#ifndef GENODE
+ end:
++#endif
+ (void)pthread_mutex_unlock(¤tContextMap->mMutex);
+
+ PROFILE_END(rv)
+@@ -1426,6 +1611,7 @@ retry:
+ memset(&scStatusStruct, 0, sizeof(scStatusStruct));
+ scStatusStruct.hCard = hCard;
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
+ sizeof(scStatusStruct), (void *) &scStatusStruct);
+
+@@ -1440,6 +1626,19 @@ retry:
+
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
++#else
++
++ struct status_struct stStr;
++
++ stStr = scStatusStruct;
++
++ /* only hCard and return value are used by the client */
++ stStr.rv = SCardStatusImpl(stStr.hCard, NULL, NULL, NULL,
++ NULL, 0, NULL);
++
++ scStatusStruct = stStr;
++
++#endif
+
+ rv = scStatusStruct.rv;
+
+@@ -2036,7 +2235,7 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
+
+ /* another thread can do SCardCancel() */
+ currentContextMap->cancellable = TRUE;
+-
++#ifndef GENODE
+ rv = MessageSendWithHeader(CMD_WAIT_READER_STATE_CHANGE,
+ currentContextMap->dwClientID,
+ sizeof(waitStatusStruct), &waitStatusStruct);
+@@ -2050,13 +2249,45 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
+ rv = MessageReceiveTimeout(CMD_WAIT_READER_STATE_CHANGE,
+ &waitStatusStruct, sizeof(waitStatusStruct),
+ currentContextMap->dwClientID, dwTime);
++#else
++
++ EHRegisterClientForEvent(event_pipe[1]);
++
++ fd_set readfds;
++ struct timeval timeout;
+
++ timeout.tv_sec = dwTime / 1000;
++ timeout.tv_usec = (dwTime % 1000) * 1000;
++
++ FD_ZERO(&readfds);
++ FD_SET(event_pipe[0], &readfds);
++
++ rv = select(event_pipe[0] + 1, &readfds, NULL, NULL, &timeout);
++
++ if ((rv > 0) && (FD_ISSET(event_pipe[0], &readfds))) {
++ /* got an event */
++ rv = read(event_pipe[0], &waitStatusStruct.rv, sizeof(waitStatusStruct.rv));
++ if (rv == sizeof(waitStatusStruct.rv)) {
++ rv = SCARD_S_SUCCESS;
++ } else {
++ fprintf(stderr, "Error reading event from pipe\n");
++ rv = SCARD_F_UNKNOWN_ERROR;
++ }
++ } else if (rv == 0) {
++ /* timeout */
++ rv = SCARD_E_TIMEOUT;
++ } else {
++ rv = SCARD_F_UNKNOWN_ERROR;
++ }
++
++#endif
+ /* another thread can do SCardCancel() */
+ currentContextMap->cancellable = FALSE;
+
+ /* timeout */
+ if (SCARD_E_TIMEOUT == rv)
+ {
++#ifndef GENODE
+ /* ask server to remove us from the event list */
+ rv = MessageSendWithHeader(CMD_STOP_WAITING_READER_STATE_CHANGE,
+ currentContextMap->dwClientID,
+@@ -2072,6 +2303,18 @@ LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
+
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
++#else
++
++ struct wait_reader_state_change waStr;
++
++ waStr = waitStatusStruct;
++
++ /* add the client fd to the list */
++ waStr.rv = EHUnregisterClientForEvent(event_pipe[1]);
++
++ waitStatusStruct = waStr;
++
++#endif
+ }
+
+ if (rv != SCARD_S_SUCCESS)
+@@ -2222,6 +2465,7 @@ LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
+ scControlStruct.dwBytesReturned = 0;
+ scControlStruct.rv = 0;
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
+ sizeof(scControlStruct), &scControlStruct);
+
+@@ -2255,6 +2499,26 @@ LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
+
+ }
+
++#else
++
++ struct control_struct ctStr;
++ DWORD dwBytesReturned;
++
++ ctStr = scControlStruct;
++
++ dwBytesReturned = ctStr.dwBytesReturned;
++
++ ctStr.rv = SCardControlImpl(ctStr.hCard, ctStr.dwControlCode,
++ pbSendBuffer, ctStr.cbSendLength,
++ pbRecvBuffer, ctStr.cbRecvLength,
++ &dwBytesReturned);
++
++ ctStr.dwBytesReturned = dwBytesReturned;
++
++ scControlStruct = ctStr;
++
++#endif
++
+ if (NULL != lpBytesReturned)
+ *lpBytesReturned = scControlStruct.dwBytesReturned;
+
+@@ -2519,6 +2783,7 @@ static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
+ /* we can get up to the communication buffer size */
+ scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
+ sizeof(scGetSetStruct), &scGetSetStruct);
+
+@@ -2533,6 +2798,38 @@ static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
+
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
++#else
++
++ if (command == SCARD_GET_ATTRIB) {
++
++ struct getset_struct gsStr;
++ DWORD cbAttrLen;
++
++ gsStr = scGetSetStruct;
++
++ cbAttrLen = gsStr.cbAttrLen;
++
++ gsStr.rv = SCardGetAttribImpl(gsStr.hCard, gsStr.dwAttrId,
++ gsStr.pbAttr, &cbAttrLen);
++
++ gsStr.cbAttrLen = cbAttrLen;
++
++ scGetSetStruct = gsStr;
++
++ } else if (command == SCARD_SET_ATTRIB) {
++
++ struct getset_struct gsStr;
++
++ gsStr = scGetSetStruct;
++
++ gsStr.rv = SCardSetAttribImpl(gsStr.hCard, gsStr.dwAttrId,
++ gsStr.pbAttr, gsStr.cbAttrLen);
++
++ scGetSetStruct = gsStr;
++
++ }
++
++#endif
+
+ if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
+ {
+@@ -2679,6 +2976,7 @@ retry:
+ scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
+ }
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
+ sizeof(scTransmitStruct), (void *) &scTransmitStruct);
+
+@@ -2700,16 +2998,51 @@ retry:
+
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
++#else
++
++ struct transmit_struct trStr;
++ SCARD_IO_REQUEST ioSendPci;
++ SCARD_IO_REQUEST ioRecvPci;
++ DWORD cbRecvLength;
++
++ trStr = scTransmitStruct;
++
++ ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
++ ioSendPci.cbPciLength = trStr.ioSendPciLength;
++ ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
++ ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
++ cbRecvLength = *pcbRecvLength;
++
++ trStr.rv = SCardTransmitImpl(trStr.hCard, &ioSendPci,
++ pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
++ pbRecvBuffer, &cbRecvLength);
++
++ if (cbRecvLength > trStr.pcbRecvLength)
++ /* The client buffer is not large enough.
++ * The pbRecvBuffer buffer will NOT be sent a few
++ * lines bellow. So no buffer overflow is expected. */
++ trStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
++
++ trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
++ trStr.ioSendPciLength = ioSendPci.cbPciLength;
++ trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
++ trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
++ trStr.pcbRecvLength = cbRecvLength;
++
++ scTransmitStruct = trStr;
++
++#endif
+
+ if (SCARD_S_SUCCESS == scTransmitStruct.rv)
+ {
++#ifndef GENODE
+ /* read the received buffer */
+ rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
+ currentContextMap->dwClientID);
+
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
+-
++#endif
+ if (pioRecvPci)
+ {
+ pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
+@@ -3070,7 +3403,9 @@ LONG SCardCancel(SCARDCONTEXT hContext)
+ {
+ SCONTEXTMAP * currentContextMap;
+ LONG rv = SCARD_S_SUCCESS;
++#ifndef GENODE
+ uint32_t dwClientID = 0;
++#endif
+ struct cancel_struct scCancelStruct;
+
+ PROFILE_START
+@@ -3092,16 +3427,18 @@ LONG SCardCancel(SCARDCONTEXT hContext)
+ goto error;
+ }
+
++#ifndef GENODE
+ /* create a new connection to the server */
+ if (ClientSetupSession(&dwClientID) != 0)
+ {
+ rv = SCARD_E_NO_SERVICE;
+ goto error;
+ }
+-
++#endif
+ scCancelStruct.hContext = hContext;
+ scCancelStruct.rv = SCARD_S_SUCCESS;
+
++#ifndef GENODE
+ rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
+ sizeof(scCancelStruct), (void *) &scCancelStruct);
+
+@@ -3115,11 +3452,29 @@ LONG SCardCancel(SCARDCONTEXT hContext)
+
+ if (rv != SCARD_S_SUCCESS)
+ goto end;
++#else
++
++ struct cancel_struct caStr;
++
++ caStr = scCancelStruct;
++
++ uint32_t fd = event_pipe[1];
++ caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
++
++ /* the client should not receive the event
++ * notification now the waiting has been cancelled */
++ EHUnregisterClientForEvent(fd);
++
++ scCancelStruct = caStr;
++
++#endif
+
+ rv = scCancelStruct.rv;
++#ifndef GENODE
+ end:
+- ClientCloseSession(dwClientID);
+
++ ClientCloseSession(dwClientID);
++#endif
+ error:
+ PROFILE_END(rv)
+ API_TRACE_OUT("")
+@@ -3314,7 +3669,12 @@ static LONG SCardCleanContext(SCONTEXTMAP * targetContextMap)
+ CHANNEL_MAP * currentChannelMap;
+
+ targetContextMap->hContext = 0;
++#ifndef GENODE
+ (void)ClientCloseSession(targetContextMap->dwClientID);
++#else
++ close(event_pipe[0]);
++ close(event_pipe[1]);
++#endif
+ targetContextMap->dwClientID = 0;
+ (void)pthread_mutex_destroy(&targetContextMap->mMutex);
+
+@@ -3490,6 +3850,7 @@ LONG SCardCheckDaemonAvailability(void)
+
+ static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
+ {
++#ifndef GENODE
+ int32_t dwClientID = currentContextMap->dwClientID;
+ LONG rv;
+
+@@ -3501,7 +3862,11 @@ static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
+ rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
+ if (rv != SCARD_S_SUCCESS)
+ return rv;
++#else
++
++ /* wait until all readers are ready */
++ RFWaitForReaderInit();
+
+ return SCARD_S_SUCCESS;
++#endif
+ }
+-
diff --git a/repos/libports/src/test/smartcard/main.cc b/repos/libports/src/test/smartcard/main.cc
new file mode 100644
index 000000000..04efa2293
--- /dev/null
+++ b/repos/libports/src/test/smartcard/main.cc
@@ -0,0 +1,104 @@
+/*
+ * \brief pcsc-lite test
+ * \author Christian Prochaska
+ * \date 2016-09-19
+ */
+
+/*
+ * Copyright (C) 2016 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#include
+#include
+
+#include
+
+int main()
+{
+ LONG rv;
+
+ SCARDCONTEXT hContext;
+
+ LPTSTR mszReaders;
+ DWORD dwReaders;
+
+ SCARD_READERSTATE state;
+
+ SCARDHANDLE hCard;
+ DWORD dwActiveProtocol;
+
+ SCARD_IO_REQUEST pioSendPci;
+
+ /* SELECT FILE 0x3F00 */
+ BYTE cmd[] = { 0x00, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 };
+
+ BYTE pbRecvBuffer[256];
+ DWORD dwRecvLength;
+
+ rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+
+ printf("SCardEstablishContext: 0x%lx\n", rv);
+
+ dwReaders = SCARD_AUTOALLOCATE;
+ rv = SCardListReaders(hContext, NULL, (LPTSTR)&mszReaders, &dwReaders);
+
+ printf("SCardListreaders: 0x%lx, %lu, %s\n", rv, dwReaders, mszReaders);
+
+ memset(&state, 0, sizeof state);
+ state.szReader = mszReaders;
+ rv = SCardGetStatusChange(hContext, 0, &state, 1);
+
+ printf("SCardGetStatusChange(): 0x%lx, %lx\n", rv, state.dwEventState);
+
+ while (state.dwEventState & SCARD_STATE_EMPTY) {
+
+ state.dwCurrentState = state.dwEventState;
+
+ rv = SCardGetStatusChange(hContext, INFINITE, &state, 1);
+
+ printf("SCardGetStatusChange(): 0x%lx, %lx\n", rv, state.dwEventState);
+ }
+
+ rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
+
+ printf("SCardConnect: 0x%lx, %lu\n", rv, dwActiveProtocol);
+
+ switch (dwActiveProtocol) {
+ case SCARD_PROTOCOL_T0:
+ printf("Protocol: T0\n");
+ pioSendPci = *SCARD_PCI_T0;
+ break;
+ case SCARD_PROTOCOL_T1:
+ printf("Protocol: T1\n");
+ pioSendPci = *SCARD_PCI_T1;
+ break;
+ }
+
+ dwRecvLength = sizeof(pbRecvBuffer);
+
+ rv = SCardTransmit(hCard, &pioSendPci, cmd, sizeof(cmd), NULL, pbRecvBuffer, &dwRecvLength);
+
+ printf("SCardTransmit: 0x%lx\n", rv);
+
+ printf("Response: ");
+ for (unsigned int i=0; i < dwRecvLength; i++)
+ printf("%02X ", pbRecvBuffer[i]);
+ printf("\n");
+
+ rv = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
+
+ printf("SCardDisconnect: 0x%lx\n", rv);
+
+ rv = SCardFreeMemory(hContext, mszReaders);
+
+ printf("SCardFreeMemory: 0x%lx\n", rv);
+
+ rv = SCardReleaseContext(hContext);
+
+ printf("SCardReleaseContext: 0x%lx\n", rv);
+
+ return 0;
+}
diff --git a/repos/libports/src/test/smartcard/target.mk b/repos/libports/src/test/smartcard/target.mk
new file mode 100644
index 000000000..bc161a7ad
--- /dev/null
+++ b/repos/libports/src/test/smartcard/target.mk
@@ -0,0 +1,5 @@
+TARGET = test-smartcard
+LIBS = pcsc-lite libc
+SRC_CC = main.cc
+
+vpath main.cc $(PRG_DIR)/..
diff --git a/tool/autopilot.list b/tool/autopilot.list
index a306a2d6b..d3faabfc9 100644
--- a/tool/autopilot.list
+++ b/tool/autopilot.list
@@ -72,3 +72,4 @@ fs_log
cpu_sampler
cpu_sampler_noux
usb_hid
+smartcard