initial commit of more code towards card emulation

I couldn't help but to spend my sunday on working towards card
emulation, including
* various state machines in the target about ISO7816 states
* tc_etu timer import from simtrace1
* req_ctx import from simtrace1 (needs renaming and simplifiation)
* USB protocol description as cardemu_prot.h
* some host-based testing code to test the state machines

The code seems to work fine throughout card reset, sending ATR and
receiving the TPDU header of the first APDU, up to the point where it
marks the TPDU header as to-be-transmitted over th bulk-in endpoint.

Sending the ATR must be done inside the firmware for timing
requirements.

From that point onwards, the host needs to respond at the very least
with a procedure byte, and some indication whether or not the card
emulator should continue to transmit data (card->reader), or receive
data (reader->card).

The code is intentionally not hooked up yet with the USB logic nor with
the UART.  I want host-based testing completed before doing that.
diff --git a/firmware/src_simtrace/card_emu.c b/firmware/src_simtrace/card_emu.c
new file mode 100644
index 0000000..cf82b72
--- /dev/null
+++ b/firmware/src_simtrace/card_emu.c
@@ -0,0 +1,694 @@
+/* ISO7816-3 state machine for the card side */
+/* (C) 2010-2015 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "utils.h"
+#include "trace.h"
+#include "iso7816_fidi.h"
+#include "tc_etu.h"
+#include "card_emu.h"
+#include "req_ctx.h"
+#include "cardemu_prot.h"
+
+
+#define NUM_SLOTS		2
+
+#define	ISO7816_3_INIT_WTIME	9600
+#define ISO7816_3_DEFAULT_WI	10
+#define ISO7816_3_ATR_LEN_MAX	(1+32)	/* TS plus 32 chars */
+
+#define ISO7816_3_PB_NULL	0x60
+
+enum iso7816_3_card_state {
+	ISO_S_WAIT_POWER,	/* waiting for power being applied */
+	ISO_S_WAIT_CLK,		/* waiting for clock being applied */
+	ISO_S_WAIT_RST,		/* waiting for reset being released */
+	ISO_S_WAIT_ATR,		/* waiting for start of ATR */
+	ISO_S_IN_ATR,		/* transmitting ATR to reader */
+	ISO_S_IN_PTS,		/* transmitting ATR to reader */
+	ISO_S_WAIT_TPDU,	/* waiting for data from reader */
+	ISO_S_IN_TPDU,		/* inside a TPDU */
+};
+
+/* detailed sub-states of ISO_S_IN_PTS */
+enum pts_state {
+	PTS_S_WAIT_REQ_PTSS,
+	PTS_S_WAIT_REQ_PTS0,
+	PTS_S_WAIT_REQ_PTS1,
+	PTS_S_WAIT_REQ_PTS2,
+	PTS_S_WAIT_REQ_PTS3,
+	PTS_S_WAIT_REQ_PCK,
+	PTS_S_WAIT_RESP_PTSS = PTS_S_WAIT_REQ_PTSS | 0x10,
+	PTS_S_WAIT_RESP_PTS0 = PTS_S_WAIT_REQ_PTS0 | 0x10,
+	PTS_S_WAIT_RESP_PTS1 = PTS_S_WAIT_REQ_PTS1 | 0x10,
+	PTS_S_WAIT_RESP_PTS2 = PTS_S_WAIT_REQ_PTS2 | 0x10,
+	PTS_S_WAIT_RESP_PTS3 = PTS_S_WAIT_REQ_PTS3 | 0x10,
+	PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10,
+};
+
+#define _PTSS	0
+#define _PTS0	1
+#define _PTS1	2
+#define _PTS2	3
+#define _PTS3	4
+#define _PCK	5
+
+enum tpdu_state {
+	TPDU_S_WAIT_CLA,
+	TPDU_S_WAIT_INS,
+	TPDU_S_WAIT_P1,
+	TPDU_S_WAIT_P2,
+	TPDU_S_WAIT_P3,
+	TPDU_S_WAIT_PB,		/* waiting for Tx of procedure byte */
+	TPDU_S_WAIT_RX,		/* waiitng for more data from reader */
+	TPDU_S_WAIT_TX,		/* waiting for more data to reader */
+};
+
+#define	_CLA	0
+#define	_INS	1
+#define	_P1	2
+#define	_P2	3
+#define	_P3	4
+
+struct card_handle {
+	enum iso7816_3_card_state state;
+
+	/* signal levels */
+	uint8_t vcc_active;	/* 1 = on, 0 = off */
+	uint8_t in_reset;	/* 1 = RST low, 0 = RST high */
+	uint8_t clocked;	/* 1 = active, 0 = inactive */
+
+	/* timing */
+	uint8_t fi;
+	uint8_t di;
+	uint8_t wi;
+
+	uint8_t tc_chan;	/* TC channel number */
+	uint8_t uart_chan;	/* UART channel */
+
+	uint32_t waiting_time;	/* in clocks */
+
+	/* ATR state machine */
+	struct {
+		uint8_t idx;
+		uint8_t len;
+		//uint8_t hist_len;
+		//uint8_t last_td;
+		uint8_t atr[ISO7816_3_ATR_LEN_MAX];
+	} atr;
+
+	/* PPS / PTS support */
+	struct {
+		enum pts_state state;
+		uint8_t req[6];
+		uint8_t resp[6];
+	} pts;
+
+	/* TPDU */
+	struct {
+		enum tpdu_state state;
+		uint8_t hdr[5];
+	} tpdu;
+
+	struct req_ctx *uart_rx_ctx;
+	struct req_ctx *uart_tx_ctx;
+
+	struct {
+		uint32_t tx_bytes;
+		uint32_t rx_bytes;
+		uint32_t pps;
+	} stats;
+};
+
+static int update_fidi(struct card_handle *ch)
+{
+	int rc;
+
+	rc = compute_fidi_ratio(ch->fi, ch->di);
+	if (rc > 0 && rc < 0x400) {
+		TRACE_DEBUG("computed Fi(%u) Di(%u) ratio: %d\n",
+			    ch->fi, ch->di, rc);
+		/* make sure UART uses new F/D ratio */
+		card_emu_uart_update_fidi(ch->uart_chan, rc);
+		/* notify ETU timer about this */
+		tc_etu_set_etu(ch->tc_chan, rc);
+	} else
+		TRACE_DEBUG("computed FiDi ration %d unsupported\n", rc);
+}
+
+/* Update the ISO 7816-3 TPDU receiver state */
+static void card_set_state(struct card_handle *ch,
+			   enum iso7816_3_card_state new_state)
+{
+	switch (new_state) {
+	case ISO_S_WAIT_POWER:
+	case ISO_S_WAIT_CLK:
+	case ISO_S_WAIT_RST:
+		/* disable Rx and Tx of UART */
+		card_emu_uart_enable(ch->uart_chan, 0);
+		break;
+	case ISO_S_WAIT_ATR:
+		/* Reset to initial Fi / Di ratio */
+		ch->fi = 1;
+		ch->di = 1;
+		update_fidi(ch);
+		/* initialize todefault WI, this will be overwritten if we
+		 * receive TC2, and it will be programmed into hardware after
+		 * ATR is finished */
+		ch->wi = ISO7816_3_DEFAULT_WI;
+		/* update waiting time to initial waiting time */
+		ch->waiting_time = ISO7816_3_INIT_WTIME;
+		tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
+		/* Set ATR sub-state to initial state */
+		ch->atr.idx = 0;
+		//set_atr_state(ch, ATR_S_WAIT_TS);
+		/* Notice that we are just coming out of reset */
+		//ch->sh.flags |= SIMTRACE_FLAG_ATR;
+		card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
+		break;
+		break;
+	case ISO_S_WAIT_TPDU:
+		/* enable the receiver, disable transmitter */
+		card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
+		break;
+	case ISO_S_IN_ATR:
+	case ISO_S_IN_PTS:
+	case ISO_S_IN_TPDU:
+		/* do nothing */
+		break;
+	}
+
+	if (ch->state == new_state)
+		return;
+
+	TRACE_DEBUG("7816 card state %u -> %u\n", ch->state, new_state);
+	ch->state = new_state;
+}
+
+
+/**********************************************************************
+ * PTS / PPS handling
+ **********************************************************************/
+
+/* Update the ATR sub-state */
+static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss)
+{
+	TRACE_DEBUG("7816 PTS state %u -> %u\n", ch->pts.state, new_ptss);
+	ch->pts.state = new_ptss;
+}
+
+/* Determine the next PTS state */
+static enum pts_state next_pts_state(struct card_handle *ch)
+{
+	uint8_t is_resp = ch->pts.state & 0x10;
+	uint8_t sstate = ch->pts.state & 0x0f;
+	uint8_t *pts_ptr;
+
+	if (!is_resp)
+		pts_ptr = ch->pts.req;
+	else
+		pts_ptr = ch->pts.resp;
+
+	switch (sstate) {
+	case PTS_S_WAIT_REQ_PTSS:
+		goto from_ptss;
+	case PTS_S_WAIT_REQ_PTS0:
+		goto from_pts0;
+	case PTS_S_WAIT_REQ_PTS1:
+		goto from_pts1;
+	case PTS_S_WAIT_REQ_PTS2:
+		goto from_pts2;
+	case PTS_S_WAIT_REQ_PTS3:
+		goto from_pts3;
+	}
+
+	if (ch->pts.state == PTS_S_WAIT_REQ_PCK)
+		return PTS_S_WAIT_RESP_PTSS;
+
+from_ptss:
+	return PTS_S_WAIT_REQ_PTS0 | is_resp;
+from_pts0:
+	if (pts_ptr[_PTS0] & (1 << 4))
+		return PTS_S_WAIT_REQ_PTS1 | is_resp;
+from_pts1:
+	if (pts_ptr[_PTS0] & (1 << 5))
+		return PTS_S_WAIT_REQ_PTS2 | is_resp;
+from_pts2:
+	if (pts_ptr[_PTS0] & (1 << 6))
+		return PTS_S_WAIT_REQ_PTS3 | is_resp;
+from_pts3:
+	return PTS_S_WAIT_REQ_PCK | is_resp;
+}
+
+
+static enum iso7816_3_card_state
+process_byte_pts(struct card_handle *ch, uint8_t byte)
+{
+	switch (ch->pts.state) {
+	case PTS_S_WAIT_REQ_PTSS:
+		ch->pts.req[_PTSS] = byte;
+		break;
+	case PTS_S_WAIT_REQ_PTS0:
+		ch->pts.req[_PTS0] = byte;
+		break;
+	case PTS_S_WAIT_REQ_PTS1:
+		ch->pts.req[_PTS1] = byte;
+		break;
+	case PTS_S_WAIT_REQ_PTS2:
+		ch->pts.req[_PTS2] = byte;
+		break;
+	case PTS_S_WAIT_REQ_PTS3:
+		ch->pts.req[_PTS3] = byte;
+		break;
+	case PTS_S_WAIT_REQ_PCK:
+		ch->pts.req[_PCK] = byte;
+		/* FIXME: check PCK */
+		memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp));
+		break;
+	}
+	/* calculate the next state and set it */
+	set_pts_state(ch, next_pts_state(ch));
+
+	return ISO_S_IN_PTS;
+}
+
+/* return a single byte to be transmitted to the reader */
+static int get_byte_pps(struct card_handle *ch, uint8_t *byte)
+{
+	/* FIXME */
+#if 0
+	switch (ch->pts.state) {
+	case PTS_S_WAIT_RESP_PTSS:
+		ch->pts.resp[_PTSS] = byte;
+		break;
+	case PTS_S_WAIT_RESP_PTS0:
+		ch->pts.resp[_PTS0] = byte;
+		break;
+	case PTS_S_WAIT_RESP_PTS1:
+		/* This must be TA1 */
+		ch->fi = byte >> 4;
+		ch->di = byte & 0xf;
+		TRACE_DEBUG("found Fi=%u Di=%u\n", ch->fi, ch->di);
+		ch->sh.flags |= SIMTRACE_FLAG_PPS_FIDI;
+		ch->pts.resp[_PTS1] = byte;
+		break;
+	case PTS_S_WAIT_RESP_PTS2:
+		ch->pts.resp[_PTS2] = byte;
+		break;
+	case PTS_S_WAIT_RESP_PTS3:
+		ch->pts.resp[_PTS3] = byte;
+		break;
+	case PTS_S_WAIT_RESP_PCK:
+		ch->pts.resp[_PCK] = byte;
+		/* FIXME: check PCK */
+		set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
+		/* update baud rate generator with Fi/Di */
+		update_fidi(ch);
+		/* Wait for the next TPDU */
+		card_set_state(ch, ISO_S_WAIT_TPDU);
+	}
+#endif
+	/* calculate the next state and set it */
+	set_pts_state(ch, next_pts_state(ch));
+
+	return 0;
+}
+
+
+/**********************************************************************
+ * TPDU handling
+ **********************************************************************/
+
+/* add a just-received TPDU byte (from reader) to USB buffer */
+static void add_tpdu_byte(struct card_handle *ch, uint8_t byte)
+{
+	struct req_ctx *rctx;
+	struct cardemu_usb_msg_rx_data *rd;
+
+	/* ensure we have a buffer */
+	if (!ch->uart_rx_ctx) {
+		ch->uart_rx_ctx = req_ctx_find_get(1, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
+		if (!ch->uart_rx_ctx)
+			return;
+		rd = (struct cardemu_usb_msg_rx_data *) ch->uart_rx_ctx->data;
+		cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
+		rctx->tot_len = sizeof(*rd);
+		rctx->idx = 0;
+	} else
+		rctx = ch->uart_rx_ctx;
+
+	rd = (struct cardemu_usb_msg_rx_data *) rctx->data;
+
+	rd->data[rctx->idx++] = byte;
+	rctx->tot_len++;
+
+	/* check if the buffer is full. If so, send it */
+	if (rctx->tot_len >= rctx->size) {
+		/* store length of data payload fild in header */
+		rd->hdr.data_len = rctx->idx;
+		req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
+		ch->uart_rx_ctx = NULL;
+		/* FIXME: call into USB code to see if this buffer can
+		 * be transmitted now */
+	}
+}
+
+static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
+{
+	TRACE_DEBUG("7816 TPDU state %u -> %u\n", ch->tpdu.state, new_ts);
+	switch (new_ts) {
+	case TPDU_S_WAIT_CLA:
+		card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
+		break;
+	case TPDU_S_WAIT_PB:
+		/* we just completed the TPDU header from reader to card
+		 * and now need to disable the receiver, enable the
+		 * transmitter and transmit the procedure byte */
+		card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
+		break;
+	}
+	ch->tpdu.state = new_ts;
+}
+
+static enum tpdu_state next_tpdu_state(struct card_handle *ch)
+{
+	switch (ch->tpdu.state) {
+	case TPDU_S_WAIT_CLA:
+		return TPDU_S_WAIT_INS;
+	case TPDU_S_WAIT_INS:
+		return TPDU_S_WAIT_P1;
+	case TPDU_S_WAIT_P1:
+		return TPDU_S_WAIT_P2;
+	case TPDU_S_WAIT_P2:
+		return TPDU_S_WAIT_P3;
+	case TPDU_S_WAIT_P3:
+		return TPDU_S_WAIT_PB;
+	/* simply stay in Rx or Tx by default */
+	case TPDU_S_WAIT_PB:
+		return TPDU_S_WAIT_PB;
+	case TPDU_S_WAIT_RX:
+		return TPDU_S_WAIT_RX;
+	case TPDU_S_WAIT_TX:
+		return TPDU_S_WAIT_TX;
+	}
+}
+
+static void send_tpdu_header(struct card_handle *ch)
+{
+	struct req_ctx *rctx;
+	struct cardemu_usb_msg_rx_data *rd;
+
+	/* if we already/still have a context, send it off */
+	if (ch->uart_rx_ctx && rctx->idx) {
+		ch->uart_rx_ctx = NULL;
+	}
+
+	/* ensure we have a new buffer */
+	ch->uart_rx_ctx = req_ctx_find_get(1, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
+	if (!ch->uart_rx_ctx)
+		return;
+	rctx = ch->uart_rx_ctx;
+	rd = (struct cardemu_usb_msg_rx_data *) rctx->data;
+
+	/* initializ header */
+	cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
+	rd->flags = CEMU_DATA_F_TPDU_HDR;
+	rctx->tot_len = sizeof(*rd) + sizeof(ch->tpdu.hdr);
+	rctx->idx = 0;
+
+	/* copy TPDU header to data field */
+	memcpy(rd->data, ch->tpdu.hdr, sizeof(ch->tpdu.hdr));
+	rd->hdr.data_len = sizeof(ch->tpdu.hdr);
+
+	req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
+}
+
+static enum iso7816_3_card_state
+process_byte_tpdu(struct card_handle *ch, uint8_t byte)
+{
+	switch (ch->tpdu.state) {
+	case TPDU_S_WAIT_CLA:
+		ch->tpdu.hdr[_CLA] = byte;
+		break;
+	case TPDU_S_WAIT_INS:
+		ch->tpdu.hdr[_INS] = byte;
+		break;
+	case TPDU_S_WAIT_P1:
+		ch->tpdu.hdr[_P1] = byte;
+		break;
+	case TPDU_S_WAIT_P2:
+		ch->tpdu.hdr[_P2] = byte;
+		break;
+	case TPDU_S_WAIT_P3:
+		ch->tpdu.hdr[_P3] = byte;
+		/* FIXME: start timer to transmit further 0x60 */
+		/* send the TPDU header as part of a procedure byte
+		 * request to the USB host */
+		send_tpdu_header(ch);
+		break;
+	case TPDU_S_WAIT_RX:
+		add_tpdu_byte(ch, byte);
+		break;
+	default:
+		TRACE_DEBUG("process_byte_tpdu() in invalid state %u\n",
+			    ch->tpdu.state);
+	}
+	set_tpdu_state(ch, next_tpdu_state(ch));
+
+	/* ensure we stay in TPDU ISO state */
+	return ISO_S_IN_TPDU;
+}
+
+/* return a single byte to be transmitted to the reader */
+static int get_byte_tpdu(struct card_handle *ch, uint8_t *byte)
+{
+	struct req_ctx *rctx;
+	struct cardemu_usb_msg_tx_data *td;
+
+	/* ensure we are aware of any data that might be pending for
+	 * transmit */
+	if (!ch->uart_tx_ctx) {
+		ch->uart_tx_ctx = req_ctx_find_get(1, RCTX_S_UART_TX_PENDING,
+						   RCTX_S_UART_TX_BUSY);
+		if (!ch->uart_tx_ctx)
+			return 0;
+
+		/* start with index zero */
+		ch->uart_tx_ctx->idx = 0;
+
+	}
+	rctx = ch->uart_tx_ctx;
+	td = (struct cardemu_usb_msg_tx_data *) rctx->data;
+
+#if 0
+	/* this must happen _after_ the byte has been transmittd */
+	switch (ch->tpdu.state) {
+	case TPDU_S_WAIT_PB:
+		if (td->flags & CEMU_DATA_F_PB_AND_TX)
+			set_tpdu_state(ch, TPDU_S_WAIT_TX);
+		else if (td->flags & CEMU_DATA_F_PB_AND_RX)
+			set_tpdu_state(ch, TPDU_S_WAIT_RX);
+		break;
+	}
+#endif
+
+	/* take the next pending byte out of the rctx */
+	*byte = td->data[rctx->idx++];
+
+	/* check if the buffer has now been fully transmitted */
+	if ((rctx->idx >= td->hdr.data_len) ||
+	    (rctx->idx + sizeof(*td) - sizeof(td->hdr) >= rctx->tot_len)) {
+		req_ctx_set_state(rctx, RCTX_S_FREE);
+		ch->uart_tx_ctx = NULL;
+		/* FIXME: call into USB code to chec if we need to
+		 * submit a free buffer to accept furthe data on bulk
+		 * out endpoint */
+	}
+
+	return 1;
+}
+
+/**********************************************************************
+ * Public API
+ **********************************************************************/
+
+/* process a single byte received from the reader */
+void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
+{
+	int new_state = -1;
+
+	ch->stats.rx_bytes++;
+
+	switch (ch->state) {
+	case ISO_S_WAIT_POWER:
+	case ISO_S_WAIT_CLK:
+	case ISO_S_WAIT_RST:
+	case ISO_S_WAIT_ATR:
+		/* we shouldn't receive any data from the reader yet! */
+		break;
+	case ISO_S_WAIT_TPDU:
+		if (byte == 0xff) {
+			new_state = process_byte_pts(ch, byte);
+			ch->stats.pps++;
+			goto out_silent;
+		}
+		/* fall-through */
+	case ISO_S_IN_TPDU:
+		new_state = process_byte_tpdu(ch, byte);
+		break;
+	case ISO_S_IN_PTS:
+		new_state = process_byte_pts(ch, byte);
+		goto out_silent;
+	}
+
+out_silent:
+	if (new_state != -1)
+		card_set_state(ch, new_state);
+}
+
+/* return a single byte to be transmitted to the reader */
+int card_emu_get_tx_byte(struct card_handle *ch, uint8_t *byte)
+{
+	int rc = 0;
+
+	switch (ch->state) {
+	case ISO_S_IN_ATR:
+		if (ch->atr.idx < ch->atr.len) {
+			*byte = ch->atr.atr[ch->atr.idx++];
+			rc = 1;
+			/* detect end of ATR */
+			if (ch->atr.idx >= ch->atr.len)
+				card_set_state(ch, ISO_S_WAIT_TPDU);
+		}
+		break;
+	case ISO_S_IN_PTS:
+		rc = get_byte_pps(ch, byte);
+		break;
+	case ISO_S_IN_TPDU:
+		rc = get_byte_tpdu(ch, byte);
+		break;
+	}
+
+	if (rc)
+		ch->stats.tx_bytes++;
+
+	return rc;
+}
+
+/* hardware driver informs us that a card I/O signal has changed */
+void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
+{
+	switch (io) {
+	case CARD_IO_VCC:
+		if (active == 0)
+			card_set_state(ch, ISO_S_WAIT_POWER);
+		else if (active == 1 && ch->vcc_active == 0)
+			card_set_state(ch, ISO_S_WAIT_CLK);
+		ch->vcc_active = active;
+		break;
+	case CARD_IO_CLK:
+		if (active == 1 && ch->state == ISO_S_WAIT_CLK)
+			card_set_state(ch, ISO_S_WAIT_RST);
+		ch->clocked = active;
+		break;
+	case CARD_IO_RST:
+		if (active == 0 && ch->in_reset &&
+		    ch->vcc_active && ch->clocked) {
+			/* FIXME: wait 400 clocks */
+			//card_set_state(ch, ISO_S_WAIT_ATR);
+			card_set_state(ch, ISO_S_IN_ATR);
+		}
+		ch->in_reset = active;
+		break;
+	}
+}
+
+/* User sets a new ATR to be returned during next card reset */
+int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len)
+{
+	if (len > sizeof(ch->atr.atr))
+		return -1;
+
+	memcpy(ch->atr.atr, atr, len);
+	ch->atr.len = len;
+	ch->atr.idx = 0;
+
+	/* FIXME: race condition with trasmitting ATR to reader? */
+
+	return 0;
+}
+
+/* hardware driver informs us that one (more) ETU has expired */
+void tc_etu_wtime_half_expired(void *handle)
+{
+	struct card_handle *ch = handle;
+	/* transmit NULL procedure byte well before waiting time expires */
+	card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL);
+}
+
+/* hardware driver informs us that one (more) ETU has expired */
+void tc_etu_wtime_expired(void *handle)
+{
+}
+
+/* shortest ATR found in smartcard_list.txt */
+static const uint8_t default_atr[] = { 0x3B, 0x02, 0x14, 0x50 };
+
+static struct card_handle card_handles[NUM_SLOTS];
+
+struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan)
+{
+	struct card_handle *ch;
+
+	if (slot_num >= ARRAY_SIZE(card_handles))
+		return NULL;
+
+	ch = &card_handles[slot_num];
+
+	memset(ch, 0, sizeof(*ch));
+
+	/* initialize the card_handle with reasonabe defaults */
+	ch->state = ISO_S_WAIT_POWER;
+	ch->vcc_active = 0;
+	ch->in_reset = 1;
+	ch->clocked = 0;
+
+	ch->fi = 0;
+	ch->di = 1;
+	ch->wi = ISO7816_3_DEFAULT_WI;
+
+	ch->tc_chan = tc_chan;
+	ch->uart_chan = uart_chan;
+	ch->waiting_time = ISO7816_3_INIT_WTIME;
+
+	ch->atr.idx = 0;
+	ch->atr.len = sizeof(default_atr);
+	memcpy(ch->atr.atr, default_atr, ch->atr.len);
+
+	ch->pts.state = PTS_S_WAIT_REQ_PTSS;
+	ch->tpdu.state = TPDU_S_WAIT_CLA;
+
+	tc_etu_init(ch->tc_chan, ch);
+
+	return ch;
+}