summaryrefslogtreecommitdiff
path: root/firmware/src/simtrace
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-07-30 19:04:55 +0200
committerHarald Welte <laforge@gnumonks.org>2011-07-30 19:04:55 +0200
commita3de0a4ac29118c3ada946a0c8f7f602c9066ec1 (patch)
tree8408d463a3ea6910d7336e24d60611da8a50b77d /firmware/src/simtrace
parentdd88fde8d2b78243c01871cabca37c9e46ebd03d (diff)
parentffbce3ea2cda51214be0bb7a107954f890f99b0d (diff)
Merge branch 'simtrace'
Diffstat (limited to 'firmware/src/simtrace')
-rw-r--r--firmware/src/simtrace/iso7816_uart.c641
-rw-r--r--firmware/src/simtrace/iso7816_uart.h6
-rw-r--r--firmware/src/simtrace/main_factory.c80
-rw-r--r--firmware/src/simtrace/main_simtrace.c165
-rw-r--r--firmware/src/simtrace/sim_switch.c95
-rw-r--r--firmware/src/simtrace/sim_switch.h7
-rw-r--r--firmware/src/simtrace/spi_flash.c144
-rw-r--r--firmware/src/simtrace/tc_etu.c128
-rw-r--r--firmware/src/simtrace/tc_etu.h4
-rw-r--r--firmware/src/simtrace/usb_strings_app.txt7
-rw-r--r--firmware/src/simtrace/usb_strings_dfu.txt6
11 files changed, 1283 insertions, 0 deletions
diff --git a/firmware/src/simtrace/iso7816_uart.c b/firmware/src/simtrace/iso7816_uart.c
new file mode 100644
index 0000000..cd1a2f0
--- /dev/null
+++ b/firmware/src/simtrace/iso7816_uart.c
@@ -0,0 +1,641 @@
+/* Driver for AT91SAM7 USART0 in ISO7816-3 mode for passive sniffing
+ * (C) 2010 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 <sys/types.h>
+#include <AT91SAM7.h>
+#include <lib_AT91SAM7.h>
+#include <openpcd.h>
+
+#include <simtrace_usb.h>
+
+#include <os/usb_handler.h>
+#include <os/dbgu.h>
+#include <os/pio_irq.h>
+
+#include "../simtrace.h"
+#include "../openpcd.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static const AT91PS_USART usart = AT91C_BASE_US0;
+
+enum iso7816_3_state {
+ ISO7816_S_RESET, /* in Reset */
+ ISO7816_S_WAIT_ATR, /* waiting for ATR to start */
+ ISO7816_S_IN_ATR, /* while we are receiving the ATR */
+ ISO7816_S_WAIT_APDU, /* waiting for start of new APDU */
+ ISO7816_S_IN_APDU, /* inside a single APDU */
+ ISO7816_S_IN_PTS, /* while we are inside the PTS / PSS */
+};
+
+/* detailed sub-states of ISO7816_S_IN_ATR */
+enum atr_state {
+ ATR_S_WAIT_TS,
+ ATR_S_WAIT_T0,
+ ATR_S_WAIT_TA,
+ ATR_S_WAIT_TB,
+ ATR_S_WAIT_TC,
+ ATR_S_WAIT_TD,
+ ATR_S_WAIT_HIST,
+ ATR_S_WAIT_TCK,
+ ATR_S_DONE,
+};
+
+/* detailed sub-states of ISO7816_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
+
+struct iso7816_3_handle {
+ enum iso7816_3_state state;
+
+ u_int8_t fi;
+ u_int8_t di;
+ u_int8_t wi;
+ u_int32_t waiting_time;
+
+ enum atr_state atr_state;
+ u_int8_t atr_idx;
+ u_int8_t atr_hist_len;
+ u_int8_t atr_last_td;
+ u_int8_t atr[64];
+
+ enum pts_state pts_state;
+ u_int8_t pts_req[6];
+ u_int8_t pts_resp[6];
+
+ struct simtrace_hdr sh;
+
+ int rctx_must_be_sent;
+ struct req_ctx *rctx;
+};
+
+struct iso7816_3_handle isoh;
+
+
+/* Table 6 from ISO 7816-3 */
+static const u_int16_t fi_table[] = {
+ 0, 372, 558, 744, 1116, 1488, 1860, 0,
+ 0, 512, 768, 1024, 1536, 2048, 0, 0
+};
+
+/* Table 7 from ISO 7816-3 */
+static const u_int8_t di_table[] = {
+ 0, 1, 2, 4, 8, 16, 0, 0,
+ 0, 0, 2, 4, 8, 16, 32, 64,
+};
+
+/* compute the F/D ratio based on Fi and Di values */
+static int compute_fidi_ratio(u_int8_t fi, u_int8_t di)
+{
+ u_int16_t f, d;
+ int ret;
+
+ if (fi >= ARRAY_SIZE(fi_table) ||
+ di >= ARRAY_SIZE(di_table))
+ return -EINVAL;
+
+ f = fi_table[fi];
+ if (f == 0)
+ return -EINVAL;
+
+ d = di_table[di];
+ if (d == 0)
+ return -EINVAL;
+
+ if (di < 8)
+ ret = f / d;
+ else
+ ret = f * d;
+
+ return ret;
+}
+
+static void refill_rctx(struct iso7816_3_handle *ih)
+{
+ struct req_ctx *rctx;
+
+ rctx = req_ctx_find_get(0, RCTX_STATE_FREE,
+ RCTX_STATE_LIBRFID_BUSY);
+ if (!rctx) {
+ ih->rctx = NULL;
+ return;
+ }
+
+ ih->sh.cmd = SIMTRACE_MSGT_DATA;
+
+ /* reserve spece at start of rctx */
+ rctx->tot_len = sizeof(struct simtrace_hdr);
+
+ ih->rctx = rctx;
+}
+
+static void send_rctx(struct iso7816_3_handle *ih)
+{
+ struct req_ctx *rctx = ih->rctx;
+
+ if (!rctx)
+ return;
+
+ /* copy the simtrace header */
+ memcpy(rctx->data, &ih->sh, sizeof(ih->sh));
+
+ req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING);
+
+ memset(&ih->sh, 0, sizeof(ih->sh));
+ ih->rctx = NULL;
+}
+
+
+/* Update the ATR sub-state */
+static void set_atr_state(struct iso7816_3_handle *ih, enum atr_state new_atrs)
+{
+ if (new_atrs == ATR_S_WAIT_TS) {
+ ih->atr_idx = 0;
+ ih->atr_hist_len = 0;
+ ih->atr_last_td = 0;
+ memset(ih->atr, 0, sizeof(ih->atr));
+ } else if (ih->atr_state == new_atrs)
+ return;
+
+ //DEBUGPCR("ATR state %u -> %u", ih->atr_state, new_atrs);
+ ih->atr_state = new_atrs;
+}
+
+#define ISO7816_3_INIT_WTIME 9600
+#define ISO7816_3_DEFAULT_WI 10
+
+static void update_fidi(struct iso7816_3_handle *ih)
+{
+ int rc;
+
+ rc = compute_fidi_ratio(ih->fi, ih->di);
+ if (rc > 0 && rc < 0x400) {
+ DEBUGPCR("computed Fi(%u) Di(%u) ratio: %d", ih->fi, ih->di, rc);
+ /* make sure UART uses new F/D ratio */
+ usart->US_CR |= AT91C_US_RXDIS | AT91C_US_RSTRX;
+ usart->US_FIDI = rc & 0x3ff;
+ usart->US_CR |= AT91C_US_RXEN | AT91C_US_STTTO;
+ /* notify ETU timer about this */
+ tc_etu_set_etu(rc);
+ } else
+ DEBUGPCRF("computed FiDi ratio %d unsupported", rc);
+}
+
+/* Update the ISO 7816-3 APDU receiver state */
+static void set_state(struct iso7816_3_handle *ih, enum iso7816_3_state new_state)
+{
+ if (new_state == ISO7816_S_RESET) {
+ usart->US_CR |= AT91C_US_RXDIS | AT91C_US_RSTRX;
+ } else if (new_state == ISO7816_S_WAIT_ATR) {
+ /* Reset to initial Fi / Di ratio */
+ ih->fi = 1;
+ ih->di = 1;
+ update_fidi(ih);
+ /* initialize todefault WI, this will be overwritten if we
+ * receive TC2, and it will be programmed into hardware after
+ * ATR is finished */
+ ih->wi = ISO7816_3_DEFAULT_WI;
+ /* update waiting time to initial waiting time */
+ ih->waiting_time = ISO7816_3_INIT_WTIME;
+ tc_etu_set_wtime(ih->waiting_time);
+ /* Set ATR sub-state to initial state */
+ set_atr_state(ih, ATR_S_WAIT_TS);
+ /* Notice that we are just coming out of reset */
+ ih->sh.flags |= SIMTRACE_FLAG_ATR;
+ }
+
+ if (ih->state == new_state)
+ return;
+
+ //DEBUGPCR("7816 state %u -> %u", ih->state, new_state);
+ ih->state = new_state;
+}
+
+/* determine the next ATR state based on received interface byte */
+static enum atr_state next_intb_state(struct iso7816_3_handle *ih, u_int8_t ch)
+{
+ switch (ih->atr_state) {
+ case ATR_S_WAIT_TD:
+ case ATR_S_WAIT_T0:
+ ih->atr_last_td = ch;
+ goto from_td;
+ case ATR_S_WAIT_TC:
+ if ((ih->atr_last_td & 0x0f) == 0x02) {
+ /* TC2 contains WI */
+ ih->wi = ch;
+ }
+ goto from_tc;
+ case ATR_S_WAIT_TB:
+ goto from_tb;
+ case ATR_S_WAIT_TA:
+ goto from_ta;
+ default:
+ DEBUGPCR("something wrong, old_state != TA");
+ return ATR_S_WAIT_TCK;
+ }
+
+from_td:
+ if (ih->atr_last_td & 0x10)
+ return ATR_S_WAIT_TA;
+from_ta:
+ if (ih->atr_last_td & 0x20)
+ return ATR_S_WAIT_TB;
+from_tb:
+ if (ih->atr_last_td & 0x40)
+ return ATR_S_WAIT_TC;
+from_tc:
+ if (ih->atr_last_td & 0x80)
+ return ATR_S_WAIT_TD;
+
+ return ATR_S_WAIT_HIST;
+}
+
+/* process an incomng ATR byte */
+static enum iso7816_3_state
+process_byte_atr(struct iso7816_3_handle *ih, u_int8_t byte)
+{
+ /* add byte to ATR buffer */
+ ih->atr[ih->atr_idx] = byte;
+ ih->atr_idx++;
+
+ switch (ih->atr_state) {
+ case ATR_S_WAIT_TS:
+ /* FIXME: if we don't have the RST line we might get this */
+ if (byte == 0) {
+ ih->atr_idx--;
+ break;
+ }
+ /* FIXME: check inverted logic */
+ set_atr_state(ih, ATR_S_WAIT_T0);
+ break;
+ case ATR_S_WAIT_T0:
+ /* obtain the number of historical bytes */
+ ih->atr_hist_len = byte & 0xf;
+ /* Mask out the hist-byte-length to indiicate T=0 */
+ set_atr_state(ih, next_intb_state(ih, byte & 0xf0));
+ break;
+ case ATR_S_WAIT_TA:
+ case ATR_S_WAIT_TB:
+ case ATR_S_WAIT_TC:
+ case ATR_S_WAIT_TD:
+ set_atr_state(ih, next_intb_state(ih, byte));
+ break;
+ case ATR_S_WAIT_HIST:
+ ih->atr_hist_len--;
+ /* after all historical bytes are recieved, go to TCK */
+ if (ih->atr_hist_len == 0)
+ set_atr_state(ih, ATR_S_WAIT_TCK);
+ break;
+ case ATR_S_WAIT_TCK:
+ /* FIXME: process and verify the TCK */
+ set_atr_state(ih, ATR_S_DONE);
+ /* send off the USB context */
+ ih->rctx_must_be_sent = 1;
+ /* update the waiting time */
+ ih->waiting_time = 960 * di_table[ih->di] * ih->wi;
+ tc_etu_set_wtime(ih->waiting_time);
+ return ISO7816_S_WAIT_APDU;
+ }
+
+ return ISO7816_S_IN_ATR;
+}
+
+/* Update the ATR sub-state */
+static void set_pts_state(struct iso7816_3_handle *ih, enum pts_state new_ptss)
+{
+ //DEBUGPCR("PTS state %u -> %u", ih->pts_state, new_ptss);
+ ih->pts_state = new_ptss;
+}
+
+/* Determine the next PTS state */
+static enum pts_state next_pts_state(struct iso7816_3_handle *ih)
+{
+ u_int8_t is_resp = ih->pts_state & 0x10;
+ u_int8_t sstate = ih->pts_state & 0x0f;
+ u_int8_t *pts_ptr;
+
+ if (!is_resp)
+ pts_ptr = ih->pts_req;
+ else
+ pts_ptr = ih->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 (ih->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_state
+process_byte_pts(struct iso7816_3_handle *ih, u_int8_t byte)
+{
+ switch (ih->pts_state) {
+ case PTS_S_WAIT_REQ_PTSS:
+ ih->pts_req[_PTSS] = byte;
+ break;
+ case PTS_S_WAIT_REQ_PTS0:
+ ih->pts_req[_PTS0] = byte;
+ break;
+ case PTS_S_WAIT_REQ_PTS1:
+ ih->pts_req[_PTS1] = byte;
+ break;
+ case PTS_S_WAIT_REQ_PTS2:
+ ih->pts_req[_PTS2] = byte;
+ break;
+ case PTS_S_WAIT_REQ_PTS3:
+ ih->pts_req[_PTS3] = byte;
+ break;
+ case PTS_S_WAIT_REQ_PCK:
+ /* FIXME: check PCK */
+ ih->pts_req[_PCK] = byte;
+ break;
+ case PTS_S_WAIT_RESP_PTSS:
+ ih->pts_resp[_PTSS] = byte;
+ break;
+ case PTS_S_WAIT_RESP_PTS0:
+ ih->pts_resp[_PTS0] = byte;
+ break;
+ case PTS_S_WAIT_RESP_PTS1:
+ /* This must be TA1 */
+ ih->fi = byte >> 4;
+ ih->di = byte & 0xf;
+ DEBUGPCR("found Fi=%u Di=%u", ih->fi, ih->di);
+ ih->pts_resp[_PTS1] = byte;
+ break;
+ case PTS_S_WAIT_RESP_PTS2:
+ ih->pts_resp[_PTS2] = byte;
+ break;
+ case PTS_S_WAIT_RESP_PTS3:
+ ih->pts_resp[_PTS3] = byte;
+ break;
+ case PTS_S_WAIT_RESP_PCK:
+ ih->pts_resp[_PCK] = byte;
+ /* FIXME: check PCK */
+ set_pts_state(ih, PTS_S_WAIT_REQ_PTSS);
+ /* update baud rate generator with Fi/Di */
+ update_fidi(ih);
+ /* Wait for the next APDU */
+ return ISO7816_S_WAIT_APDU;
+ }
+ /* calculate the next state and set it */
+ set_pts_state(ih, next_pts_state(ih));
+
+ return ISO7816_S_IN_PTS;
+}
+
+static void process_byte(struct iso7816_3_handle *ih, u_int8_t byte)
+{
+ int new_state = -1;
+ struct req_ctx *rctx;
+
+ if (!ih->rctx)
+ refill_rctx(ih);
+
+ switch (ih->state) {
+ case ISO7816_S_RESET:
+ break;
+ case ISO7816_S_WAIT_ATR:
+ case ISO7816_S_IN_ATR:
+ new_state = process_byte_atr(ih, byte);
+ break;
+ case ISO7816_S_WAIT_APDU:
+ if (byte == 0xff) {
+ new_state = process_byte_pts(ih, byte);
+ goto out_silent;
+ }
+ case ISO7816_S_IN_APDU:
+ new_state = ISO7816_S_IN_APDU;
+ break;
+ case ISO7816_S_IN_PTS:
+ new_state = process_byte_pts(ih, byte);
+ goto out_silent;
+ }
+
+ /* The USB buffer could be gone in case the timer expired or code above
+ * this line explicitly sent it off */
+ if (!ih->rctx)
+ refill_rctx(ih);
+
+ rctx = ih->rctx;
+ if (!rctx) {
+ DEBUGPCR("==> Lost byte, missing rctx");
+ return;
+ }
+
+ /* store the byte in the USB request context */
+ rctx->data[rctx->tot_len] = byte;
+ rctx->tot_len++;
+
+ if (rctx->tot_len >= rctx->size || ih->rctx_must_be_sent) {
+ ih->rctx_must_be_sent = 0;
+ send_rctx(ih);
+ }
+
+out_silent:
+ if (new_state != -1)
+ set_state(ih, new_state);
+}
+
+/* timeout of work waiting time during receive */
+void iso7816_wtime_expired(void)
+{
+ /* Always flush the URB at Rx timeout as this indicates end of APDU */
+ if (isoh.rctx) {
+ isoh.sh.flags |= SIMTRACE_FLAG_WTIME_EXP;
+ send_rctx(&isoh);
+ }
+ if (isoh.state == ISO7816_S_IN_PTS) {
+ /* Timout during PTS: Card does not support PTS */
+ }
+ set_state(&isoh, ISO7816_S_WAIT_APDU);
+}
+
+static __ramfunc void usart_irq(void)
+{
+ u_int32_t csr = usart->US_CSR;
+ u_int8_t octet;
+
+ //DEBUGP("USART IRQ, CSR=0x%08x\n", csr);
+
+ if (csr & AT91C_US_RXRDY) {
+ /* at least one character received */
+ octet = usart->US_RHR & 0xff;
+ //DEBUGP("%02x ", octet);
+ process_byte(&isoh, octet);
+ }
+
+ if (csr & AT91C_US_TXRDY) {
+ /* nothing to transmit anymore */
+ }
+
+ if (csr & (AT91C_US_PARE|AT91C_US_FRAME|AT91C_US_OVRE)) {
+ /* FIXME: some error has occurrerd */
+ }
+}
+
+/* handler for the RST input pin state change */
+static void reset_pin_irq(u_int32_t pio)
+{
+ if (!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, pio)) {
+ DEBUGPCR("nRST");
+ set_state(&isoh, ISO7816_S_RESET);
+ } else {
+ DEBUGPCR("RST");
+ set_state(&isoh, ISO7816_S_WAIT_ATR);
+ }
+}
+
+void iso_uart_dump(void)
+{
+ u_int32_t csr = usart->US_CSR;
+
+ DEBUGPCR("USART CSR=0x%08x", csr);
+}
+
+void iso_uart_rst(unsigned int state)
+{
+ DEBUGPCR("USART set nRST set state=%u", state);
+ switch (state) {
+ case 0:
+ AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST);
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST);
+ break;
+ case 1:
+ AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST);
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST);
+ break;
+ default:
+ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST);
+ break;
+ }
+}
+
+void iso_uart_rx_mode(void)
+{
+ DEBUGPCR("USART Entering Rx Mode");
+ /* Enable receive interrupts */
+ usart->US_IER = AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME |
+ AT91C_US_PARE | AT91C_US_NACK | AT91C_US_ITERATION;
+
+ /* call interrupt handler once to set initial state RESET / ATR */
+ reset_pin_irq(SIMTRACE_PIO_nRST);
+}
+
+void iso_uart_clk_master(unsigned int master)
+{
+ DEBUGPCR("USART Clock Master %u", master);
+ if (master) {
+ usart->US_MR = AT91C_US_USMODE_ISO7816_0 | AT91C_US_CLKS_CLOCK |
+ AT91C_US_CHRL_8_BITS | AT91C_US_NBSTOP_1_BIT |
+ AT91C_US_CKLO;
+ usart->US_BRGR = (0x0000 << 16) | 16;
+ } else {
+ usart->US_MR = AT91C_US_USMODE_ISO7816_0 | AT91C_US_CLKS_EXT |
+ AT91C_US_CHRL_8_BITS | AT91C_US_NBSTOP_1_BIT |
+ AT91C_US_CKLO;
+ usart->US_BRGR = (0x0000 << 16) | 0x0001;
+ }
+}
+
+void iso_uart_init(void)
+{
+ DEBUGPCR("USART Initializing");
+
+ refill_rctx(&isoh);
+
+ /* make sure we get clock from the power management controller */
+ AT91F_US0_CfgPMC();
+
+ /* configure all 3 signals as input */
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, SIMTRACE_PIO_IO, SIMTRACE_PIO_CLK);
+ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST);
+
+ AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_US0,
+ OPENPCD_IRQ_PRIO_USART,
+ AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &usart_irq);
+ AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_US0);
+
+ usart->US_CR = AT91C_US_RXDIS | AT91C_US_TXDIS |
+ (AT91C_US_RSTRX | AT91C_US_RSTTX);
+ /* FIXME: wait for some time */
+ usart->US_CR = AT91C_US_RXDIS | AT91C_US_TXDIS;
+
+ /* ISO7816 T=0 mode with external clock input */
+ usart->US_MR = AT91C_US_USMODE_ISO7816_0 | AT91C_US_CLKS_EXT |
+ AT91C_US_CHRL_8_BITS | AT91C_US_NBSTOP_1_BIT |
+ AT91C_US_CKLO;
+
+ /* Disable all interrupts */
+ usart->US_IDR = 0xff;
+ /* Clock Divider = 1, i.e. no division of SCLK */
+ usart->US_BRGR = (0x0000 << 16) | 0x0001;
+ /* Disable Receiver Time-out */
+ usart->US_RTOR = 0;
+ /* Disable Transmitter Timeguard */
+ usart->US_TTGR = 0;
+
+ pio_irq_register(SIMTRACE_PIO_nRST, &reset_pin_irq);
+ AT91F_PIO_CfgInputFilter(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST);
+ pio_irq_enable(SIMTRACE_PIO_nRST);
+}
diff --git a/firmware/src/simtrace/iso7816_uart.h b/firmware/src/simtrace/iso7816_uart.h
new file mode 100644
index 0000000..ed1c898
--- /dev/null
+++ b/firmware/src/simtrace/iso7816_uart.h
@@ -0,0 +1,6 @@
+
+void iso_uart_dump(void);
+void iso_uart_rst(unsigned int state);
+void iso_uart_rx_mode(void);
+void iso_uart_clk_master(unsigned int master);
+void iso_uart_init(void);
diff --git a/firmware/src/simtrace/main_factory.c b/firmware/src/simtrace/main_factory.c
new file mode 100644
index 0000000..3585fa6
--- /dev/null
+++ b/firmware/src/simtrace/main_factory.c
@@ -0,0 +1,80 @@
+/* SIMtrace factory programming
+ * (C) 2011 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 <include/lib_AT91SAM7.h>
+#include <include/openpcd.h>
+#include <os/dbgu.h>
+#include <os/led.h>
+#include <os/pcd_enumerate.h>
+#include <os/usb_handler.h>
+#include "../openpcd.h"
+#include "../simtrace.h"
+#include <os/main.h>
+#include <os/pio_irq.h>
+
+#include <simtrace/tc_etu.h>
+#include <simtrace/iso7816_uart.h>
+#include <simtrace/sim_switch.h>
+
+void _init_func(void)
+{
+ /* low-level hardware initialization */
+ pio_irq_init();
+ spiflash_init();
+
+ /* high-level protocol */
+ //opicc_usbapi_init();
+ led_switch(1, 0);
+ led_switch(2, 1);
+}
+
+static void help(void)
+{
+ DEBUGPCR("f: read flash ID\r\n");
+}
+
+int _main_dbgu(char key)
+{
+ static int i = 0;
+ DEBUGPCRF("main_dbgu");
+
+ switch (key) {
+ case 'f':
+ spiflash_id();
+ break;
+ case '?':
+ help();
+ break;
+ }
+
+ return -EINVAL;
+}
+
+void _main_func(void)
+{
+ /* first we try to get rid of pending to-be-sent stuff */
+ usb_out_process();
+
+ /* next we deal with incoming requests from USB EP1 (OUT) */
+ usb_in_process();
+
+ udp_unthrottle();
+}
diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c
new file mode 100644
index 0000000..f919690
--- /dev/null
+++ b/firmware/src/simtrace/main_simtrace.c
@@ -0,0 +1,165 @@
+/* OpenPICC Main Program
+ * (C) 2006 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 <include/lib_AT91SAM7.h>
+#include <include/openpcd.h>
+#include <os/dbgu.h>
+#include <os/led.h>
+#include <os/pcd_enumerate.h>
+#include <os/usb_handler.h>
+#include "../openpcd.h"
+#include "../simtrace.h"
+#include <os/main.h>
+#include <os/pio_irq.h>
+
+#include <simtrace/tc_etu.h>
+#include <simtrace/iso7816_uart.h>
+#include <simtrace/sim_switch.h>
+
+enum simtrace_md {
+ SIMTRACE_MD_OFF,
+ SIMTRACE_MD_SNIFFER,
+ SIMTRACE_MD_MITM,
+};
+
+#define UART1_PINS (SIMTRACE_PIO_nRST_PH | \
+ SIMTRACE_PIO_CLK_PH | \
+ SIMTRACE_PIO_CLK_PH_T | \
+ SIMTRACE_PIO_IO_PH_RX | \
+ SIMTRACE_PIO_IO_PH_TX)
+
+#define UART0_PINS (SIMTRACE_PIO_nRST | \
+ SIMTRACE_PIO_CLK | \
+ SIMTRACE_PIO_CLK_T | \
+ SIMTRACE_PIO_IO | \
+ SIMTRACE_PIO_IO_T)
+
+static void simtrace_set_mode(enum simtrace_md mode)
+{
+ switch (mode) {
+ case SIMTRACE_MD_SNIFFER:
+ DEBUGPCR("MODE: SNIFFER\n");
+
+ /* switch UART1 pins to input, no pull-up */
+ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, UART1_PINS);
+ AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, UART1_PINS);
+
+ /* switch VCC_SIM pin into output mode, as in the first
+ * generation prototype we use it directly to supply Vcc
+ * to the SIM */
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_SIM);
+ AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_SIM);
+
+ /* switch UART0 pins to 'ISO7816 card mode' */
+ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, UART0_PINS);
+ AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, UART0_PINS);
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, SIMTRACE_PIO_IO, SIMTRACE_PIO_CLK);
+ sim_switch_mode(1, 1);
+ break;
+ case SIMTRACE_MD_MITM:
+ DEBUGPCR("MODE: MITM\n");
+ /* switch UART1 pins to 'ISO7816 card mode' */
+ /* switch UART0 pins to 'ISO7816 reader mode' */
+ sim_switch_mode(0, 0);
+ break;
+ }
+}
+
+void _init_func(void)
+{
+ /* low-level hardware initialization */
+ pio_irq_init();
+ iso_uart_init();
+ tc_etu_init();
+ sim_switch_init();
+
+ usbtest_init();
+
+ /* high-level protocol */
+ //opicc_usbapi_init();
+ led_switch(1, 0);
+ led_switch(2, 1);
+
+ iso_uart_rx_mode();
+ simtrace_set_mode(SIMTRACE_MD_SNIFFER);
+}
+
+
+static void help(void)
+{
+ DEBUGPCR("r: iso uart Rx mode\r\n"
+ "c: toggle clock master/slave\r\n"
+ "l: set nRST to low (active)\r\n"
+ "h: set nRST to high (inactive)\r\n"
+ "o: set nRST to input\r\n"
+ "r: set Rx mode for UART\r\n"
+ "s: disconnect SIM bus switch\r\n"
+ "S: connect SIM bus switch\r\n");
+}
+
+int _main_dbgu(char key)
+{
+ static int i = 0;
+ DEBUGPCRF("main_dbgu");
+
+ switch (key) {
+ case 's':
+ simtrace_set_mode(SIMTRACE_MD_MITM);
+ break;
+ case 'S':
+ simtrace_set_mode(SIMTRACE_MD_SNIFFER);
+ break;
+ case 'r':
+ iso_uart_rx_mode();
+ break;
+ case 'c':
+ iso_uart_clk_master(i++ & 1);
+ break;
+ case 'l':
+ iso_uart_rst(0);
+ break;
+ case 'h':
+ iso_uart_rst(1);
+ break;
+ case 'o':
+ iso_uart_rst(2);
+ break;
+ case 'd':
+ iso_uart_dump();
+ break;
+ case '?':
+ help();
+ break;
+ }
+
+ return -EINVAL;
+}
+
+void _main_func(void)
+{
+ /* first we try to get rid of pending to-be-sent stuff */
+ usb_out_process();
+
+ /* next we deal with incoming requests from USB EP1 (OUT) */
+ usb_in_process();
+
+ udp_unthrottle();
+}
diff --git a/firmware/src/simtrace/sim_switch.c b/firmware/src/simtrace/sim_switch.c
new file mode 100644
index 0000000..f83290f
--- /dev/null
+++ b/firmware/src/simtrace/sim_switch.c
@@ -0,0 +1,95 @@
+/*
+ * (C) 2011 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 <sys/types.h>
+#include <AT91SAM7.h>
+#include <lib_AT91SAM7.h>
+#include <openpcd.h>
+
+#include <simtrace_usb.h>
+
+#include <os/usb_handler.h>
+#include <os/dbgu.h>
+#include <os/pio_irq.h>
+
+#include "../simtrace.h"
+#include "../openpcd.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+void sim_switch_mode(int connect_io, int connect_misc)
+{
+ if (connect_io)
+ AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_IO_SW);
+ else
+ AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_IO_SW);
+
+ if (connect_misc)
+ AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_SC_SW);
+ else
+ AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_SC_SW);
+}
+
+static void sw_sim_irq(u_int32_t pio)
+{
+
+ if (!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, pio))
+ DEBUGPCR("SIM card inserted");
+ else
+ DEBUGPCR("SIM card removed");
+}
+
+static void vcc_phone_irq(u_int32_t pio)
+{
+ if (!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, pio))
+ DEBUGPCR("VCC_PHONE off");
+ else
+ DEBUGPCR("VCC_PHONE on");
+}
+
+void sim_switch_init(void)
+{
+ DEBUGPCR("ISO_SW Initializing");
+
+ /* make sure we get clock from the power management controller */
+ AT91F_US0_CfgPMC();
+
+ /* configure both signals as output */
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_SC_SW |
+ SIMTRACE_PIO_IO_SW);
+
+ /* configure sim card detect */
+ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_SW_SIM);
+ AT91F_PIO_CfgInputFilter(AT91C_BASE_PIOA, SIMTRACE_PIO_SW_SIM);
+ pio_irq_register(SIMTRACE_PIO_SW_SIM, &sw_sim_irq);
+ pio_irq_enable(SIMTRACE_PIO_SW_SIM);
+ /* configure VCC_PHONE detection */
+ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_PHONE);
+ AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_PHONE);
+ AT91F_PIO_CfgInputFilter(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_PHONE);
+ pio_irq_register(SIMTRACE_PIO_VCC_PHONE, &vcc_phone_irq);
+ pio_irq_enable(SIMTRACE_PIO_VCC_PHONE);
+
+#if 0
+ AT91F_ADC_CfgPMC();
+ AT91F_ADC_EnableChannel(AT91C_BASE_ADC, AT91C_ADC_CH7);
+#endif
+}
diff --git a/firmware/src/simtrace/sim_switch.h b/firmware/src/simtrace/sim_switch.h
new file mode 100644
index 0000000..01a6a66
--- /dev/null
+++ b/firmware/src/simtrace/sim_switch.h
@@ -0,0 +1,7 @@
+#ifndef SIMTRACE_ISO_SW_H
+#define SIMTRACE_ISO_SW_H
+
+void sim_switch_mode(int connect_io, int connect_misc);
+void sim_switch_init(void);
+
+#endif
diff --git a/firmware/src/simtrace/spi_flash.c b/firmware/src/simtrace/spi_flash.c
new file mode 100644
index 0000000..98bc369
--- /dev/null
+++ b/firmware/src/simtrace/spi_flash.c
@@ -0,0 +1,144 @@
+/* Driver for a SST25VF040B spi flash attached to AT91SAM7 SPI
+ * (C) 2011 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 <sys/types.h>
+#include <AT91SAM7.h>
+#include <lib_AT91SAM7.h>
+#include <openpcd.h>
+
+#include <simtrace_usb.h>
+
+#include <os/usb_handler.h>
+#include <os/dbgu.h>
+#include <os/pio_irq.h>
+
+#include "../simtrace.h"
+#include "../openpcd.h"
+
+#define DEBUGPSPI DEBUGP
+//#define DEBUGPSPI(x, y ...) do { } while (0)
+
+static const AT91PS_SPI pSPI = AT91C_BASE_SPI;
+
+void spiflash_write_protect(int on)
+{
+ if (on)
+ AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, PIO_SPIF_nWP);
+ else
+ AT91F_PIO_SetOutput(AT91C_BASE_PIOA, PIO_SPIF_nWP);
+}
+
+#define SPI_PERIPHA (PIO_SPIF_SCK|PIO_SPIF_MOSI|PIO_SPIF_MISO|PIO_SPIF_nCS)
+
+static __ramfunc void spi_irq(void)
+{
+ u_int32_t status = pSPI->SPI_SR;
+
+ AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_SPI);
+}
+
+void spiflash_init(void)
+{
+ DEBUGP("spiflash_init\r\n");
+
+ /* activate and enable the write protection */
+ AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, PIO_SPIF_nWP);
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, PIO_SPIF_nWP);
+ spiflash_write_protect(1);
+
+ /* Configure PIOs for SCK, MOSI, MISO and nCS */
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, SPI_PERIPHA, 0);
+
+ AT91F_SPI_CfgPMC();
+ /* Spansion flash in v1.0p only supprts Mode 3 or Mode 0 */
+ /* Mode 3: CPOL=1 nCPHA=0 CSAAT=0 BITS=0(8) MCK/2 */
+ AT91F_SPI_CfgCs(AT91C_BASE_SPI, 0, AT91C_SPI_CPOL |
+ AT91C_SPI_BITS_8 |
+ (64 << 8));
+
+ /* SPI master mode, fixed CS, CS = 0 */
+ AT91F_SPI_CfgMode(AT91C_BASE_SPI, AT91C_SPI_MSTR |
+ AT91C_SPI_PS_FIXED |
+ (0 << 16));
+
+ /* configure interrupt controller for SPI IRQ */
+ AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SPI,
+ OPENPCD_IRQ_PRIO_SPI,
+ AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &spi_irq);
+ //AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SPI);
+
+ /* Enable the SPI Controller */
+ AT91F_SPI_Enable(AT91C_BASE_SPI);
+ AT91F_SPI_EnableIt(AT91C_BASE_SPI, AT91C_SPI_MODF |
+ AT91C_SPI_OVRES |
+ AT91C_SPI_ENDRX |
+ AT91C_SPI_ENDTX);
+}
+
+static int spi_transceive(const u_int8_t *tx_data, u_int16_t tx_len,
+ u_int8_t *rx_data, u_int16_t *rx_len)
+{
+ u_int16_t tx_cur = 0;
+ u_int16_t rx_len_max = 0;
+ u_int16_t rx_cnt = 0;
+
+ DEBUGPSPI("spi_transceive: enter(tx_len=%u) ", tx_len);
+
+ if (rx_len) {
+ rx_len_max = *rx_len;
+ *rx_len = 0;
+ }
+
+ //AT91F_SPI_Enable(pSPI);
+ while (1) {
+ u_int32_t sr = pSPI->SPI_SR;
+ u_int8_t tmp;
+ if (sr & AT91C_SPI_RDRF) {
+ tmp = pSPI->SPI_RDR;
+ rx_cnt++;
+ if (rx_len && *rx_len < rx_len_max)
+ rx_data[(*rx_len)++] = tmp;
+ }
+ if (sr & AT91C_SPI_TDRE) {
+ if (tx_len > tx_cur)
+ pSPI->SPI_TDR = tx_data[tx_cur++];
+ }
+ if (tx_cur >= tx_len && rx_cnt >= tx_len)
+ break;
+ }
+ //AT91F_SPI_Disable(pSPI);
+ if (rx_data)
+ DEBUGPSPI(" leave(%02x %02x)\r\n", rx_data[0], rx_data[1]);
+ else
+ DEBUGPSPI("leave()\r\n");
+
+ return 0;
+}
+
+void spiflash_id(void)
+{
+ const u_int8_t tx_data[] = { 0x9f, 0, 0, 0 };
+ u_int8_t rx_data[] = { 0,0,0,0 };
+ u_int16_t rx_len = sizeof(rx_data);
+
+ spi_transceive(tx_data, sizeof(tx_data), rx_data, &rx_len);
+ DEBUGP("SPI ID: %02x %02x %02x\n", rx_data[1], rx_data[2], rx_data[3]);
+}
diff --git a/firmware/src/simtrace/tc_etu.c b/firmware/src/simtrace/tc_etu.c
new file mode 100644
index 0000000..fc52033
--- /dev/null
+++ b/firmware/src/simtrace/tc_etu.c
@@ -0,0 +1,128 @@
+/* SimTrace TC (Timer / Clock) support code
+ * (C) 2006 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 <lib_AT91SAM7.h>
+#include <AT91SAM7.h>
+#include <os/dbgu.h>
+
+#include "../openpcd.h"
+
+static AT91PS_TCB tcb;
+static AT91PS_TC tcetu = AT91C_BASE_TC0;
+
+static u_int16_t waiting_time = 9600;
+static u_int16_t clocks_per_etu = 372;
+static u_int16_t wait_events;
+
+static __ramfunc void tc_etu_irq(void)
+{
+ u_int32_t sr = tcetu->TC_SR;
+ static u_int16_t nr_events;
+
+ if (sr & AT91C_TC_ETRGS) {
+ /* external trigger, i.e. we have seen a bit on I/O */
+ //DEBUGPCR("tE");
+ nr_events = 0;
+ /* Make sure we don't accept any additional external trigger */
+ /* Enabling the line below will cause race conditions. We
+ * thus re-trigger at all zero-bits in the byte and thus wait
+ * up to 12 etu longer than required */
+ //tcetu->TC_CMR &= ~AT91C_TC_ENETRG;
+ }
+
+ if (sr & AT91C_TC_CPCS) {
+ /* Compare C event has occurred, i.e. 1 etu expired */
+ //DEBUGPCR("tC");
+ nr_events++;
+ if (nr_events >= wait_events) {
+ /* enable external triggers again to catch start bit */
+ tcetu->TC_CMR |= AT91C_TC_ENETRG;
+
+ /* disable and re-enable clock to make it stop */
+ tcetu->TC_CCR = AT91C_TC_CLKDIS;
+ tcetu->TC_CCR = AT91C_TC_CLKEN;
+
+ //DEBUGPCR("%u", nr_events);
+
+ /* Indicate that the waiting time has expired */
+ iso7816_wtime_expired();
+ }
+ }
+}
+
+static void recalc_nr_events(void)
+{
+ wait_events = waiting_time/12;
+ /* clocks_per_etu * 12 equals 'sbit + 8 data bits + parity + 2 stop bits */
+ tcetu->TC_RC = clocks_per_etu * 12;
+}
+
+void tc_etu_set_wtime(u_int16_t wtime)
+{
+ waiting_time = wtime;
+ recalc_nr_events();
+ //DEBUGPCR("wtime=%u, actually waiting %u", wtime, wait_events * 12);
+}
+
+void tc_etu_set_etu(u_int16_t etu)
+{
+ clocks_per_etu = etu;
+ recalc_nr_events();
+}
+
+void tc_etu_init(void)
+{
+ /* Cfg PA4(TCLK0), PA0(TIOA0), PA1(TIOB0) */
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0,
+ AT91C_PA4_TCLK0 | AT91C_PA0_TIOA0 | AT91C_PA1_TIOB0);
+
+ AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC,
+ ((unsigned int) 1 << AT91C_ID_TC0));
+
+ /* Connect TCLK0 to XC0 */
+ tcb->TCB_BMR &= ~(AT91C_TCB_TC0XC0S);
+ tcb->TCB_BMR |= AT91C_TCB_TC0XC0S_TCLK0;
+
+ /* Register Interrupt handler */
+ AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_TC0,
+ OPENPCD_IRQ_PRIO_TC_FDT,
+ AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &tc_etu_irq);
+ AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_TC0);
+
+ /* enable interrupts for Compare-C and External Trigger */
+ tcetu->TC_IER = AT91C_TC_CPCS | AT91C_TC_ETRGS;
+
+ tcetu->TC_CMR = AT91C_TC_CLKS_XC0 | /* XC0 (TCLK0) clock */
+ AT91C_TC_WAVE | /* Wave Mode */
+ AT91C_TC_ETRGEDG_FALLING |/* Ext trig on falling edge */
+ AT91C_TC_EEVT_TIOB | /* Ext trigger is TIOB0 */
+ AT91C_TC_ENETRG | /* Enable ext. trigger */
+ AT91C_TC_WAVESEL_UP_AUTO |/* Wave mode UP */
+ AT91C_TC_ACPA_SET | /* Set TIOA0 on A compare */
+ AT91C_TC_ACPC_CLEAR | /* Clear TIOA0 on C compare */
+ AT91C_TC_ASWTRG_CLEAR; /* Clear TIOa0 on software trigger */
+
+ tc_etu_set_etu(372);
+
+ /* Enable master clock for TC0 */
+ tcetu->TC_CCR = AT91C_TC_CLKEN;
+
+ /* Reset to start timers */
+ tcb->TCB_BCR = 1;
+}
diff --git a/firmware/src/simtrace/tc_etu.h b/firmware/src/simtrace/tc_etu.h
new file mode 100644
index 0000000..59d9031
--- /dev/null
+++ b/firmware/src/simtrace/tc_etu.h
@@ -0,0 +1,4 @@
+
+void tc_etu_set_wtime(u_int16_t wtime);
+void tc_etu_set_etu(u_int16_t etu);
+void tc_etu_init(void);
diff --git a/firmware/src/simtrace/usb_strings_app.txt b/firmware/src/simtrace/usb_strings_app.txt
new file mode 100644
index 0000000..02cf326
--- /dev/null
+++ b/firmware/src/simtrace/usb_strings_app.txt
@@ -0,0 +1,7 @@
+SimTrace DFU Interface - Application Partition
+SimTrace DFU Interface - Bootloader Partition
+SimTrace DFU Interface - RAM
+sysmocom - systems for mobile communications GmbH
+SimTrace SIM Sniffer - Runtime Mode
+SimTrace Runtime Configuration
+SimTrace Runtime Interface
diff --git a/firmware/src/simtrace/usb_strings_dfu.txt b/firmware/src/simtrace/usb_strings_dfu.txt
new file mode 100644
index 0000000..2f65684
--- /dev/null
+++ b/firmware/src/simtrace/usb_strings_dfu.txt
@@ -0,0 +1,6 @@
+sysmocom - systems for mobile communications GmbH
+SimTrace SIM Sniffer - DFU Mode
+SimTrace DFU Configuration
+SimTrace DFU Interface - Application Partition
+SimTrace DFU Interface - Bootloader Partition
+SimTrace DFU Interface - RAM
personal git repositories of Harald Welte. Your mileage may vary