summaryrefslogtreecommitdiff
path: root/firmware/src
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/src')
-rw-r--r--firmware/src/dfu/dfu.c173
-rw-r--r--firmware/src/dfu/dfu.h26
-rw-r--r--firmware/src/openpcd.h7
-rw-r--r--firmware/src/os/dbgu.c2
-rw-r--r--firmware/src/os/req_ctx.c6
-rw-r--r--firmware/src/os/req_ctx.h2
-rw-r--r--firmware/src/os/usb_descriptors_openpcd.h14
-rw-r--r--firmware/src/pcd/usb_strings_app.txt1
-rw-r--r--firmware/src/pcd/usb_strings_dfu.txt1
-rw-r--r--firmware/src/picc/usb_strings_app.txt1
-rw-r--r--firmware/src/picc/usb_strings_dfu.txt1
-rw-r--r--firmware/src/simtrace.h41
-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
-rw-r--r--firmware/src/start/Cstartup.S3
-rw-r--r--firmware/src/start/Cstartup_app.S2
25 files changed, 1528 insertions, 35 deletions
diff --git a/firmware/src/dfu/dfu.c b/firmware/src/dfu/dfu.c
index 8425c28..0e22256 100644
--- a/firmware/src/dfu/dfu.c
+++ b/firmware/src/dfu/dfu.c
@@ -1,5 +1,5 @@
/* USB Device Firmware Update Implementation for OpenPCD
- * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ * (C) 2006-2011 by Harald Welte <hwelte@hmw-consulting.de>
*
* This ought to be compliant to the USB DFU Spec 1.0 as available from
* http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
@@ -37,6 +37,7 @@
#include <compile.h>
#define SAM7DFU_SIZE 0x4000
+#define SAM7DFU_RAM_SIZE 0x2000
/* If debug is enabled, we need to access debug functions from flash
* and therefore have to omit flashing */
@@ -69,6 +70,12 @@
#define led2on() AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2)
#define led2off() AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2)
+static int past_manifest = 0;
+static int switch_to_ram = 0; /* IRQ handler requests main to jump to RAM */
+static u_int16_t usb_if_nr = 0; /* last SET_INTERFACE */
+static u_int16_t usb_if_alt_nr = 0; /* last SET_INTERFACE AltSetting */
+static u_int16_t usb_if_alt_nr_dnload = 0; /* AltSetting during last dnload */
+
static void __dfufunc udp_init(void)
{
/* Set the PLL USB Divider */
@@ -210,14 +217,37 @@ static void __dfufunc udp_ep0_send_stall(void)
}
-static u_int8_t *ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
+static int first_download = 1;
+static u_int8_t *ptr, *ptr_max;
static __dfudata u_int8_t dfu_status;
__dfudata u_int32_t dfu_state = DFU_STATE_appIDLE;
static u_int32_t pagebuf32[AT91C_IFLASH_PAGE_SIZE/4];
-static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)
+static void chk_first_dnload_set_ptr(void)
+{
+ if (!first_download)
+ return;
+
+ switch (usb_if_alt_nr) {
+ case 0:
+ ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
+ ptr_max = AT91C_IFLASH + AT91C_IFLASH_SIZE - ENVIRONMENT_SIZE;
+ break;
+ case 1:
+ ptr = (u_int8_t *) AT91C_IFLASH;
+ ptr_max = AT91C_IFLASH + SAM7DFU_SIZE;
+ break;
+ case 2:
+ ptr = (u_int8_t *) AT91C_ISRAM + SAM7DFU_RAM_SIZE;
+ ptr_max = AT91C_ISRAM + AT91C_ISRAM_SIZE;
+ break;
+ }
+ first_download = 0;
+}
+
+static int __dfufunc handle_dnload_flash(u_int16_t val, u_int16_t len)
{
- volatile u_int32_t *p = (volatile u_int32_t *)ptr;
+ volatile u_int32_t *p;
u_int8_t *pagebuf = (u_int8_t *) pagebuf32;
int i;
@@ -238,13 +268,20 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)
dfu_status = DFU_STATUS_errADDRESS;
return RET_STALL;
}
+ chk_first_dnload_set_ptr();
+ p = (volatile u_int32_t *)ptr;
+
if (len == 0) {
DEBUGP("zero-size write -> MANIFEST_SYNC ");
- flash_page(p);
+ if (((unsigned long)p % AT91C_IFLASH_PAGE_SIZE) != 0)
+ flash_page(p);
dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
+ first_download = 1;
return RET_ZLP;
}
- if (ptr + len >= (u_int8_t *) AT91C_IFLASH + AT91C_IFLASH_SIZE - ENVIRONMENT_SIZE ) {
+
+ /* check if we would exceed end of memory */
+ if (ptr + len > ptr_max) {
DEBUGP("end of write exceeds flash end ");
dfu_state = DFU_STATE_dfuERROR;
dfu_status = DFU_STATUS_errADDRESS;
@@ -256,10 +293,10 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)
DEBUGR(hexdump(pagebuf, len));
- /* we can only access the write buffer with correctly aligned
- * 32bit writes ! */
#ifndef DEBUG_DFU_NOFLASH
DEBUGP("copying ");
+ /* we can only access the write buffer with correctly aligned
+ * 32bit writes ! */
for (i = 0; i < len/4; i++) {
*p++ = pagebuf32[i];
/* If we have filled a page buffer, flash it */
@@ -274,6 +311,57 @@ static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)
return RET_ZLP;
}
+static int __dfufunc handle_dnload_ram(u_int16_t val, u_int16_t len)
+{
+ DEBUGE("download ");
+
+ if (len > AT91C_IFLASH_PAGE_SIZE) {
+ /* Too big. Not that we'd really care, but it's a
+ * DFU protocol violation */
+ DEBUGP("length exceeds flash page size ");
+ dfu_state = DFU_STATE_dfuERROR;
+ dfu_status = DFU_STATUS_errADDRESS;
+ return RET_STALL;
+ }
+ chk_first_dnload_set_ptr();
+
+ if (len == 0) {
+ DEBUGP("zero-size write -> MANIFEST_SYNC ");
+ dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
+ first_download = 1;
+ return RET_ZLP;
+ }
+
+ /* check if we would exceed end of memory */
+ if (ptr + len >= ptr_max) {
+ DEBUGP("end of write exceeds RAM end ");
+ dfu_state = DFU_STATE_dfuERROR;
+ dfu_status = DFU_STATUS_errADDRESS;
+ return RET_STALL;
+ }
+
+ /* drectly copy into RAM */
+ DEBUGP("try_to_recv=%u ", len);
+ udp_ep0_recv_data(ptr, len);
+
+ DEBUGR(hexdump(ptr, len));
+
+ ptr += len;
+
+ return RET_ZLP;
+}
+
+static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)
+{
+ usb_if_alt_nr_dnload = usb_if_alt_nr;
+ switch (usb_if_alt_nr) {
+ case 2:
+ return handle_dnload_ram(val, len);
+ default:
+ return handle_dnload_flash(val, len);
+ }
+}
+
#define AT91C_IFLASH_END ((u_int8_t *)AT91C_IFLASH + AT91C_IFLASH_SIZE)
static __dfufunc int handle_upload(u_int16_t val, u_int16_t len)
{
@@ -285,9 +373,12 @@ static __dfufunc int handle_upload(u_int16_t val, u_int16_t len)
udp_ep0_send_stall();
return -EINVAL;
}
+ chk_first_dnload_set_ptr();
- if (ptr + len > AT91C_IFLASH_END)
+ if (ptr + len > AT91C_IFLASH_END) {
len = AT91C_IFLASH_END - (u_int8_t *)ptr;
+ first_download = 1;
+ }
udp_ep0_send_data((char *)ptr, len);
ptr+= len;
@@ -486,7 +577,16 @@ int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req,
case DFU_STATE_dfuMANIFEST:
switch (req) {
case USB_REQ_DFU_GETSTATUS:
+ /* we don't want to change to WAIT_RST, as it
+ * would mean that we can not support another
+ * DFU transaction before doing the actual
+ * reset. Instead, we switch to idle and note
+ * that we've already been through MANIFST in
+ * the global variable 'past_manifest'.
+ */
+ //dfu_state = DFU_STATE_dfuMANIFEST_WAIT_RST;
dfu_state = DFU_STATE_dfuIDLE;
+ past_manifest = 1;
handle_getstatus();
break;
case USB_REQ_DFU_GETSTATE:
@@ -595,7 +695,7 @@ __dfustruct const struct _dfu_desc dfu_cfg_descriptor = {
.bLength = USB_DT_CONFIG_SIZE,
.bDescriptorType = USB_DT_CONFIG,
.wTotalLength = USB_DT_CONFIG_SIZE +
- 2* USB_DT_INTERFACE_SIZE +
+ 3* USB_DT_INTERFACE_SIZE +
USB_DT_DFU_SIZE,
.bNumInterfaces = 1,
.bConfigurationValue = 1,
@@ -637,6 +737,21 @@ __dfustruct const struct _dfu_desc dfu_cfg_descriptor = {
.iInterface = 0,
#endif
},
+ .uif[2] = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0x00,
+ .bAlternateSetting = 0x02,
+ .bNumEndpoints = 0x00,
+ .bInterfaceClass = 0xfe,
+ .bInterfaceSubClass = 0x01,
+ .bInterfaceProtocol = 0x02,
+#ifdef CONFIG_USB_STRING
+ .iInterface = 6,
+#else
+ .iInterface = 0,
+#endif
+ },
.func_dfu = DFU_FUNC_DESC,
};
@@ -820,9 +935,11 @@ static __dfufunc void dfu_udp_ep0_handler(void)
udp_ep0_send_stall();
break;
case STD_SET_INTERFACE:
- DEBUGE("SET INTERFACE ");
- /* FIXME: store the interface number somewhere, once
+ DEBUGE("SET INTERFACE(if=%d, alt=%d) ", wIndex, wValue);
+ /* store the interface number somewhere, once
* we need to support DFU flashing DFU */
+ usb_if_alt_nr = wValue;
+ usb_if_nr = wIndex;
udp_ep0_send_zlp();
break;
default:
@@ -858,12 +975,22 @@ static __dfufunc void dfu_udp_irq(void)
cur_config = 0;
if (dfu_state == DFU_STATE_dfuMANIFEST_WAIT_RST ||
- dfu_state == DFU_STATE_dfuMANIFEST) {
- AT91F_RSTSoftReset(AT91C_BASE_RSTC, AT91C_RSTC_PROCRST|
- AT91C_RSTC_PERRST|
- AT91C_RSTC_EXTRST);
+ dfu_state == DFU_STATE_dfuMANIFEST ||
+ past_manifest) {
+ AT91F_DBGU_Printk("sam7dfu: switching to APP mode\r\n");
+ switch (usb_if_alt_nr_dnload) {
+ case 2:
+ switch_to_ram = 1;
+ break;
+ default:
+ /* reset back into the main application */
+ AT91F_RSTSoftReset(AT91C_BASE_RSTC,
+ AT91C_RSTC_PROCRST|
+ AT91C_RSTC_PERRST|
+ AT91C_RSTC_EXTRST);
+ break;
+ }
}
-
}
if (isr & AT91C_UDP_EPINT0)
@@ -902,7 +1029,7 @@ void __dfufunc dfu_main(void)
AT91F_DBGU_Init();
AT91F_DBGU_Printk("\n\r\n\rsam7dfu - AT91SAM7 USB DFU bootloader\n\r"
- "(C) 2006-2008 by Harald Welte <hwelte@hmw-consulting.de>\n\r"
+ "(C) 2006-2011 by Harald Welte <hwelte@hmw-consulting.de>\n\r"
"This software is FREE SOFTWARE licensed under GNU GPL\n\r");
AT91F_DBGU_Printk("Version " COMPILE_SVNREV
" compiled " COMPILE_DATE
@@ -945,6 +1072,16 @@ void __dfufunc dfu_main(void)
if( i== 0) {
AT91F_WDTRestart(AT91C_BASE_WDTC);
}
+ if (switch_to_ram) {
+ void (*ram_app_entry)(void);
+ int i;
+ for (i = 0; i < 32; i++)
+ AT91F_AIC_DisableIt(AT91C_BASE_AIC, i);
+ /* jump into RAM */
+ AT91F_DBGU_Printk("JUMP TO RAM\r\n");
+ ram_app_entry = AT91C_ISRAM + SAM7DFU_RAM_SIZE;
+ ram_app_entry();
+ }
}
}
diff --git a/firmware/src/dfu/dfu.h b/firmware/src/dfu/dfu.h
index a4184b4..c898197 100644
--- a/firmware/src/dfu/dfu.h
+++ b/firmware/src/dfu/dfu.h
@@ -61,6 +61,16 @@
.bInterfaceSubClass = 0x01, \
.bInterfaceProtocol = 0x01, \
.iInterface = 2, \
+ }, { \
+ .bLength = USB_DT_INTERFACE_SIZE, \
+ .bDescriptorType = USB_DT_INTERFACE, \
+ .bInterfaceNumber = 0x03, \
+ .bAlternateSetting = 0x00, \
+ .bNumEndpoints = 0x00, \
+ .bInterfaceClass = 0xfe, \
+ .bInterfaceSubClass = 0x01, \
+ .bInterfaceProtocol = 0x01, \
+ .iInterface = 3, \
}, \
}
#else
@@ -78,8 +88,18 @@
}, { \
.bLength = USB_DT_INTERFACE_SIZE, \
.bDescriptorType = USB_DT_INTERFACE, \
- .bInterfaceNumber = 0x02, \
- .bAlternateSetting = 0x00, \
+ .bInterfaceNumber = 0x01, \
+ .bAlternateSetting = 0x01, \
+ .bNumEndpoints = 0x00, \
+ .bInterfaceClass = 0xfe, \
+ .bInterfaceSubClass = 0x01, \
+ .bInterfaceProtocol = 0x01, \
+ .iInterface = 0, \
+ }, { \
+ .bLength = USB_DT_INTERFACE_SIZE, \
+ .bDescriptorType = USB_DT_INTERFACE, \
+ .bInterfaceNumber = 0x01, \
+ .bAlternateSetting = 0x02, \
.bNumEndpoints = 0x00, \
.bInterfaceClass = 0xfe, \
.bInterfaceSubClass = 0x01, \
@@ -98,7 +118,7 @@
struct _dfu_desc {
struct usb_config_descriptor ucfg;
- struct usb_interface_descriptor uif[2];
+ struct usb_interface_descriptor uif[3];
struct usb_dfu_func_descriptor func_dfu;
};
diff --git a/firmware/src/openpcd.h b/firmware/src/openpcd.h
index a65cd0e..3bc890e 100644
--- a/firmware/src/openpcd.h
+++ b/firmware/src/openpcd.h
@@ -10,11 +10,13 @@
#define USB_VENDOR_ID OPENPCD_VENDOR_ID
-#ifdef OLIMEX
+#if defined(OLIMEX) || defined(SIMTRACE)
#define OPENPCD_PIO_LED2 AT91C_PIO_PA17
#define OPENPCD_PIO_LED1 AT91C_PIO_PA18
#define OPENPCD_PIO_UDP_CNX AT91C_PIO_PA24
-#define OPENPCD_PIO_UDP_PUP AT91C_PIO_PA16
+#define OPENPCD_PIO_UDP_PUPv4 AT91C_PIO_PA16
+#define PIO_BOOTLDR AT91C_PIO_PA19 /* B1 used as bootloader switch */
+#define USB_PRODUCT_ID SIMTRACE_PRODUCT_ID
#else
#if defined(PCD)
#define OPENPCD_PIO_UDP_CNX AT91C_PIO_PA15
@@ -166,6 +168,7 @@
#define OPENPCD_IRQ_PRIO_SPI AT91C_AIC_PRIOR_HIGHEST
#define OPENPCD_IRQ_PRIO_SSC (AT91C_AIC_PRIOR_HIGHEST-1)
#define OPENPCD_IRQ_PRIO_SYS (AT91C_AIC_PRIOR_HIGHEST-2)
+#define OPENPCD_IRQ_PRIO_USART (AT91C_AIC_PRIOR_HIGHEST-3)
#define OPENPCD_IRQ_PRIO_TC_FDT (AT91C_AIC_PRIOR_LOWEST+3)
#define OPENPCD_IRQ_PRIO_UDP (AT91C_AIC_PRIOR_LOWEST+2)
#define OPENPCD_IRQ_PRIO_PIT (AT91C_AIC_PRIOR_LOWEST+1)
diff --git a/firmware/src/os/dbgu.c b/firmware/src/os/dbgu.c
index 026b56b..28d86a4 100644
--- a/firmware/src/os/dbgu.c
+++ b/firmware/src/os/dbgu.c
@@ -147,7 +147,7 @@ void AT91F_DBGU_Init(void)
sysirq_register(AT91SAM7_SYSIRQ_DBGU, &DBGU_irq_handler);
AT91F_DBGU_Printk("\n\r");
- AT91F_DBGU_Printk("(C) 2006 by Harald Welte <hwelte@hmw-consulting.de>\n\r"
+ AT91F_DBGU_Printk("(C) 2006-2011 by Harald Welte <hwelte@hmw-consulting.de>\n\r"
"This software is FREE SOFTWARE licensed under GNU GPL\n\r");
AT91F_DBGU_Printk("Version " COMPILE_SVNREV
" compiled " COMPILE_DATE
diff --git a/firmware/src/os/req_ctx.c b/firmware/src/os/req_ctx.c
index 73b6035..cc8d57b 100644
--- a/firmware/src/os/req_ctx.c
+++ b/firmware/src/os/req_ctx.c
@@ -28,9 +28,9 @@
/* FIXME: locking, FIFO order processing */
-#ifdef __AT91SAM7S64__
-#define NUM_RCTX_SMALL 4
-#define NUM_RCTX_LARGE 2
+#if defined(__AT91SAM7S64__) || defined(RUN_FROM_RAM)
+#define NUM_RCTX_SMALL 16
+#define NUM_RCTX_LARGE 1
#else
#define NUM_RCTX_SMALL 8
#define NUM_RCTX_LARGE 4
diff --git a/firmware/src/os/req_ctx.h b/firmware/src/os/req_ctx.h
index ac9ab3f..94b5c5a 100644
--- a/firmware/src/os/req_ctx.h
+++ b/firmware/src/os/req_ctx.h
@@ -2,7 +2,7 @@
#define _REQ_CTX_H
#define RCTX_SIZE_LARGE 2048
-#define RCTX_SIZE_SMALL 64
+#define RCTX_SIZE_SMALL 128
#define MAX_HDRSIZE sizeof(struct openpcd_hdr)
#define MAX_REQSIZE (64-MAX_HDRSIZE)
diff --git a/firmware/src/os/usb_descriptors_openpcd.h b/firmware/src/os/usb_descriptors_openpcd.h
index ceb7ff6..58c54ec 100644
--- a/firmware/src/os/usb_descriptors_openpcd.h
+++ b/firmware/src/os/usb_descriptors_openpcd.h
@@ -20,8 +20,8 @@ const struct usb_device_descriptor dev_descriptor = {
.idProduct = USB_PRODUCT_ID,
.bcdDevice = 0x0030, /* Version 0.3 */
#ifdef CONFIG_USB_STRING
- .iManufacturer = 3,
- .iProduct = 4,
+ .iManufacturer = 4,
+ .iProduct = 5,
.iSerialNumber = 0,
#else
.iManufacturer = 0,
@@ -36,7 +36,7 @@ struct _desc {
struct usb_interface_descriptor uif;
struct usb_endpoint_descriptor ep[3];
#ifdef CONFIG_DFU
- struct usb_interface_descriptor uif_dfu[2];
+ struct usb_interface_descriptor uif_dfu[3];
#endif
};
@@ -46,9 +46,9 @@ const struct _desc cfg_descriptor = {
.bDescriptorType = USB_DT_CONFIG,
.wTotalLength = USB_DT_CONFIG_SIZE +
#ifdef CONFIG_DFU
- 3 * USB_DT_INTERFACE_SIZE +
+ 4 * USB_DT_INTERFACE_SIZE +
3 * USB_DT_ENDPOINT_SIZE,
- .bNumInterfaces = 3,
+ .bNumInterfaces = 4,
#else
1 * USB_DT_INTERFACE_SIZE +
3 * USB_DT_ENDPOINT_SIZE,
@@ -56,7 +56,7 @@ const struct _desc cfg_descriptor = {
#endif
.bConfigurationValue = 1,
#ifdef CONFIG_USB_STRING
- .iConfiguration = 5,
+ .iConfiguration = 6,
#else
.iConfiguration = 0,
#endif
@@ -73,7 +73,7 @@ const struct _desc cfg_descriptor = {
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0xff,
#ifdef CONFIG_USB_STRING
- .iInterface = 6,
+ .iInterface = 7,
#else
.iInterface = 0,
#endif
diff --git a/firmware/src/pcd/usb_strings_app.txt b/firmware/src/pcd/usb_strings_app.txt
index a4e9f57..ce295dc 100644
--- a/firmware/src/pcd/usb_strings_app.txt
+++ b/firmware/src/pcd/usb_strings_app.txt
@@ -1,5 +1,6 @@
OpenPCD DFU Interface - Application Partition
OpenPCD DFU Interface - Bootloader Partition
+OpenPCD DFU Interface - RAM
bitmanufaktur.de IT Solutions and hmw-consulting.de
OpenPCD RFID Reader - Runtime Mode
OpenPCD Runtime Configuration
diff --git a/firmware/src/pcd/usb_strings_dfu.txt b/firmware/src/pcd/usb_strings_dfu.txt
index a7714b7..9b18e60 100644
--- a/firmware/src/pcd/usb_strings_dfu.txt
+++ b/firmware/src/pcd/usb_strings_dfu.txt
@@ -3,3 +3,4 @@ OpenPCD RFID Reader - DFU Mode
OpenPCD DFU Configuration
OpenPCD DFU Interface - Application Partition
OpenPCD DFU Interface - Bootloader Partition
+OpenPCD DFU Interface - RAM
diff --git a/firmware/src/picc/usb_strings_app.txt b/firmware/src/picc/usb_strings_app.txt
index d892c72..5e8ed56 100644
--- a/firmware/src/picc/usb_strings_app.txt
+++ b/firmware/src/picc/usb_strings_app.txt
@@ -1,5 +1,6 @@
OpenPICC DFU Interface - Application Partition
OpenPICC DFU Interface - Bootloader Partition
+OpenPICC DFU Interface - RAM
bitmanufaktur.de IT Solutions and hmw-consulting.de
OpenPICC RFID Simulator - Runtime Mode
OpenPICC Runtime Configuration
diff --git a/firmware/src/picc/usb_strings_dfu.txt b/firmware/src/picc/usb_strings_dfu.txt
index 681c30a..008259d 100644
--- a/firmware/src/picc/usb_strings_dfu.txt
+++ b/firmware/src/picc/usb_strings_dfu.txt
@@ -3,3 +3,4 @@ OpenPICC RFID Simulator - DFU Mode
OpenPIIC DFU Configuration
OpenPICC DFU Interface - Application Partition
OpenPICC DFU Interface - Bootloader Partition
+OpenPICC DFU Interface - RAM
diff --git a/firmware/src/simtrace.h b/firmware/src/simtrace.h
new file mode 100644
index 0000000..40ed3ab
--- /dev/null
+++ b/firmware/src/simtrace.h
@@ -0,0 +1,41 @@
+
+#define USB_VENDOR_ID OPENPCD_VENDOR_ID
+
+#ifdef SIMTRACE
+#define OPENPCD_PIO_LED2 AT91C_PIO_PA17
+#define OPENPCD_PIO_LED1 AT91C_PIO_PA18
+#define OPENPCD_PIO_UDP_CNX AT91C_PIO_PA29
+#define OPENPCD_PIO_UDP_PUP AT91C_PIO_PA16
+#define USB_PRODUCT_ID SIMTRACE_PRODUCT_ID
+#else
+#error "unknown PCB"
+#endif
+
+/* 7816 UART for SIM-card side */
+#define SIMTRACE_PIO_CLK AT91C_PA2_SCK0
+#define SIMTRACE_PIO_CLK_T AT91C_PA4_TCLK0
+#define SIMTRACE_PIO_IO AT91C_PA6_TXD0
+#define SIMTRACE_PIO_IO_T AT91C_PA1_TIOB0
+#define SIMTRACE_PIO_nRST AT91C_PIO_PA7
+#define SIMTRACE_PIO_SW_SIM AT91C_PIO_PA8
+
+/* 7816 UART for phone side */
+#define SIMTRACE_PIO_nRST_PH AT91C_PIO_PA24
+#define SIMTRACE_PIO_CLK_PH AT91C_PA23_SCK1
+#define SIMTRACE_PIO_CLK_PH_T AT91C_PA28_TCLK1
+#define SIMTRACE_PIO_IO_PH_TX AT91C_PA22_TXD1
+#define SIMTRACE_PIO_IO_PH_RX AT91C_PA21_RXD1
+
+/* bus switch for SIM card connection */
+#define SIMTRACE_PIO_SC_SW AT91C_PIO_PA20
+#define SIMTRACE_PIO_IO_SW AT91C_PIO_PA19
+
+#define SIMTRACE_PIO_VCC_SIM AT91C_PIO_PA5
+#define SIMTRACE_PIO_VCC_PHONE AT91C_PIO_PA30
+
+/* SPI flash */
+#define PIO_SPIF_nWP AT91C_PIO_PA15
+#define PIO_SPIF_SCK AT91C_PA14_SPCK
+#define PIO_SPIF_MOSI AT91C_PA13_MOSI
+#define PIO_SPIF_MISO AT91C_PA12_MISO
+#define PIO_SPIF_nCS AT91C_PA11_NPCS0
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
diff --git a/firmware/src/start/Cstartup.S b/firmware/src/start/Cstartup.S
index a28b400..e262b8f 100644
--- a/firmware/src/start/Cstartup.S
+++ b/firmware/src/start/Cstartup.S
@@ -98,6 +98,9 @@
/* Olimex SAM7-Pxxx boards have a button B1 on PA19 that is low-active */
.equ PIO_BOOTLDR, (1 << 19)
#define CONFIG_DFU_SWITCH_INV
+#elif defined(SIMTRACE)
+ .equ PIO_BOOTLDR, (1 << 31)
+#define CONFIG_DFU_SWITCH_INV
#else
#error please define PIO_BOOTLDR for your board
#endif
diff --git a/firmware/src/start/Cstartup_app.S b/firmware/src/start/Cstartup_app.S
index 448cc93..197be66 100644
--- a/firmware/src/start/Cstartup_app.S
+++ b/firmware/src/start/Cstartup_app.S
@@ -79,6 +79,7 @@
.global _startup
.func _startup
_startup:
+#ifndef RUN_FROM_RAM
/* Relocate .data section (copy from Flash to RAM) */
ldr r1, =_etext
ldr r2, =_data
@@ -87,6 +88,7 @@ loop_r: cmp r2, r3
ldrlo r0, [r1], #4
strlo r0, [r2], #4
blo loop_r
+#endif
/* Clear .bss section (Zero init) */
mov r0, #0
personal git repositories of Harald Welte. Your mileage may vary