diff options
-rw-r--r-- | openpcd/firmware/Makefile | 3 | ||||
-rw-r--r-- | openpcd/firmware/include/cl_rc632.h | 17 | ||||
-rw-r--r-- | openpcd/firmware/include/rfid_layer2_iso14443a.h | 86 | ||||
-rw-r--r-- | openpcd/firmware/lib/bitops.h | 33 | ||||
-rw-r--r-- | openpcd/firmware/src/main_reqa.c | 10 | ||||
-rw-r--r-- | openpcd/firmware/src/rc632_highlevel.c | 293 |
6 files changed, 314 insertions, 128 deletions
diff --git a/openpcd/firmware/Makefile b/openpcd/firmware/Makefile index 78c9716..77fcfd6 100644 --- a/openpcd/firmware/Makefile +++ b/openpcd/firmware/Makefile @@ -72,7 +72,8 @@ SRC = # List C source files here which must be compiled in ARM-Mode. # use file-extension c for "c-only"-files SRCARM = lib/lib_AT91SAM7.c src/pcd_enumerate.c src/fifo.c src/dbgu.c \ - src/led.c src/rc632.c src/req_ctx.c src/trigger.c src/main.c \ + src/led.c src/rc632.c src/rc632_highlevel.c src/req_ctx.c \ + src/trigger.c src/main.c \ src/$(TARGET).c compil/SrcWinARM/Cstartup_SAM7.c # List C++ source files here. diff --git a/openpcd/firmware/include/cl_rc632.h b/openpcd/firmware/include/cl_rc632.h index 627e281..1be38be 100644 --- a/openpcd/firmware/include/cl_rc632.h +++ b/openpcd/firmware/include/cl_rc632.h @@ -221,6 +221,23 @@ enum rc632_reg_channel_redundancy { RC632_CR_CRC3309 = 0x20, }; +enum rc632_reg_timer_control { + RC632_TMR_START_TX_BEGIN = 0x01, + RC632_TMR_START_TX_END = 0x02, + RC632_TMR_STOP_RX_BEGIN = 0x04, + RC632_TMR_STOP_RX_END = 0x08, +}; + +enum rc632_reg_timer_irq { + RC632_IRQ_LO_ALERT = 0x01, + RC632_IRQ_HI_ALERT = 0x02, + RC632_IRQ_IDLE = 0x04, + RC632_IRQ_RX = 0x08, + RC632_IRQ_TX = 0x10, + RC632_IRQ_TIMER = 0x20, + + RC632_IRQ_SET = 0x80, +}; #endif diff --git a/openpcd/firmware/include/rfid_layer2_iso14443a.h b/openpcd/firmware/include/rfid_layer2_iso14443a.h new file mode 100644 index 0000000..936d902 --- /dev/null +++ b/openpcd/firmware/include/rfid_layer2_iso14443a.h @@ -0,0 +1,86 @@ +#ifndef _RFID_ISO14443A_H +#define _RFID_ISO14443A_H + +enum rfid_frametype { + RFID_14443A_FRAME_REGULAR, + RFID_14443B_FRAME_REGULAR, + RFID_MIFARE_FRAME, +}; + + +enum rfid_14443a_opt { + RFID_OPT_14443A_SPEED_RX = 0x00000001, + RFID_OPT_14443A_SPEED_TX = 0x00000002, +}; + +enum rfid_14443_opt_speed { + RFID_14443A_SPEED_106K = 0x01, + RFID_14443A_SPEED_212K = 0x02, + RFID_14443A_SPEED_424K = 0x04, + RFID_14443A_SPEED_848K = 0x08, +}; + +#include <sys/types.h> + +/* protocol definitions */ + +/* ISO 14443-3, Chapter 6.3.1 */ +enum iso14443a_sf_cmd { + ISO14443A_SF_CMD_REQA = 0x26, + ISO14443A_SF_CMD_WUPA = 0x52, + ISO14443A_SF_CMD_OPT_TIMESLOT = 0x35, /* Annex C */ + /* 40 to 4f and 78 to 7f: proprietary */ +}; + +struct iso14443a_atqa { + u_int8_t bf_anticol:5, + rfu1:1, + uid_size:2; + u_int8_t proprietary:4, + rfu2:4; +}; + +#define ISO14443A_HLTA 0x5000 + +/* ISO 14443-3, Chapter 6.3.2 */ +struct iso14443a_anticol_cmd { + unsigned char sel_code; + unsigned char nvb; + unsigned char uid_bits[5]; +}; + +enum iso14443a_anticol_sel_code { + ISO14443A_AC_SEL_CODE_CL1 = 0x93, + ISO14443A_AC_SEL_CODE_CL2 = 0x95, + ISO14443A_AC_SEL_CODE_CL3 = 0x97, +}; + +#define ISO14443A_BITOFCOL_NONE 0xffffffff + + +enum iso14443a_level { + ISO14443A_LEVEL_NONE, + ISO14443A_LEVEL_CL1, + ISO14443A_LEVEL_CL2, + ISO14443A_LEVEL_CL3, +}; + +enum iso14443a_state { + ISO14443A_STATE_ERROR, + ISO14443A_STATE_NONE, + ISO14443A_STATE_REQA_SENT, + ISO14443A_STATE_ATQA_RCVD, + ISO14443A_STATE_NO_BITFRAME_ANTICOL, + ISO14443A_STATE_ANTICOL_RUNNING, + ISO14443A_STATE_SELECTED, +}; + +/* Section 6.1.2 values in usec, rounded up to next usec */ +#define ISO14443A_FDT_ANTICOL_LAST1 92 /* 1236 / fc = 91.15 usec */ +#define ISO14443A_FDT_ANTICOL_LAST0 87 /* 1172 / fc = 86.43 usec */ + +#define ISO14443_CARRIER_FREQ 13560000 +#define ISO14443A_FDT_OTHER_LAST1(n) (((n*128+84)*1000000)/ISO14443_CARRIER_FREQ) + + +#endif /* _ISO14443A_H */ diff --git a/openpcd/firmware/lib/bitops.h b/openpcd/firmware/lib/bitops.h new file mode 100644 index 0000000..428c9a6 --- /dev/null +++ b/openpcd/firmware/lib/bitops.h @@ -0,0 +1,33 @@ + .macro bitop, instr + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 + save_and_disable_irqs ip + ldrb r2, [r1, r0, lsr #3] + \instr r2, r2, r3 + strb r2, [r1, r0, lsr #3] + restore_irqs ip + mov pc, lr + .endm + +/** + * testop - implement a test_and_xxx_bit operation. + * @instr: operational instruction + * @store: store instruction + * + * Note: we can trivially conditionalise the store instruction + * to avoid dirting the data cache. + */ + .macro testop, instr, store + add r1, r1, r0, lsr #3 + and r3, r0, #7 + mov r0, #1 + save_and_disable_irqs ip + ldrb r2, [r1] + tst r2, r0, lsl r3 + \instr r2, r2, r0, lsl r3 + \store r2, [r1] + restore_irqs ip + moveq r0, #0 + mov pc, lr + .endm diff --git a/openpcd/firmware/src/main_reqa.c b/openpcd/firmware/src/main_reqa.c index 8d0b170..64cceb0 100644 --- a/openpcd/firmware/src/main_reqa.c +++ b/openpcd/firmware/src/main_reqa.c @@ -1,12 +1,15 @@ -#include "rc632_highlevel.h" #include "rc632.h" #include "dbgu.h" +#include "led.h" #include "trigger.h" +#include "pcd_enumerate.h" +#include <rfid_layer2_iso14443a.h> +#include <string.h> void _init_func(void) { rc632_init(); - udp_init(); + //udp_init(); trigger_init(); } @@ -15,11 +18,12 @@ void _main_func(void) { struct iso14443a_atqa atqa; - memset(&atqa, 0, sizeof(atqua)); + memset(&atqa, 0, sizeof(atqa)); trigger_pulse(); if (rc632_iso14443a_transceive_sf(ISO14443A_SF_CMD_WUPA, &atqa) < 0) DEBUGPCRF("error during transceive_sf"); + led_toggle(2); } diff --git a/openpcd/firmware/src/rc632_highlevel.c b/openpcd/firmware/src/rc632_highlevel.c index 9a50df1..e039bc3 100644 --- a/openpcd/firmware/src/rc632_highlevel.c +++ b/openpcd/firmware/src/rc632_highlevel.c @@ -2,106 +2,180 @@ * (C) 2006 by Harald Welte <laforge@gnumonks.org> */ +#include <sys/types.h> +#include <string.h> +#include <errno.h> +#include <cl_rc632.h> +#include "rc632.h" +#include "dbgu.h" +#include <rfid_layer2_iso14443a.h> + +/* initially we use the same values as cm5121 */ +#define OPENPCD_CW_CONDUCTANCE 0x3f +#define OPENPCD_MOD_CONDUCTANCE 0x3f +#define OPENPCD_14443A_BITPHASE 0xa9 +#define OPENPCD_14443A_THRESHOLD 0xff +#define OPENPCD_14443B_BITPHASE 0xad +#define OPENPCD_14443B_THRESHOLD 0xff + +/* calculate best 8bit prescaler and divisor for given usec timeout */ +static int best_prescaler(u_int64_t timeout, u_int8_t *prescaler, + u_int8_t *divisor) +{ + u_int8_t bst_prescaler, best_divisor, i; + int64_t smallest_diff; + + smallest_diff = 0x7fffffffffffffff; + bst_prescaler = 0; + + for (i = 0; i < 21; i++) { + u_int64_t clk, tmp_div, res; + int64_t diff; + clk = 13560000 / (1 << i); + tmp_div = (clk * timeout) / 1000000; + tmp_div++; + + if (tmp_div > 0xff) + continue; + + res = 1000000 / (clk / tmp_div); + diff = res - timeout; + + if (diff < 0) + continue; + + if (diff < smallest_diff) { + bst_prescaler = i; + best_divisor = tmp_div; + smallest_diff = diff; + } + } + + *prescaler = bst_prescaler; + *divisor = best_divisor; + + DEBUGP("timeout %u usec, prescaler = %u, divisor = %u\n", + timeout, bst_prescaler, best_divisor); + + return 0; +} + + static int -rc632_iso14443a_init(void) +rc632_timer_set(u_int64_t timeout) { int ret; + u_int8_t prescaler, divisor; + + ret = best_prescaler(timeout, &prescaler, &divisor); + + rc632_reg_write(RC632_REG_TIMER_CLOCK, prescaler & 0x1f); + rc632_reg_write(RC632_REG_TIMER_CONTROL, + RC632_TMR_START_TX_END|RC632_TMR_STOP_RX_BEGIN); + + /* clear timer irq bit */ + rc632_set_bits(RC632_REG_INTERRUPT_RQ, RC632_IRQ_TIMER); + + rc632_reg_write(RC632_REG_TIMER_RELOAD, divisor); + + return ret; +} + +/* Wait until RC632 is idle or TIMER IRQ has happened */ +static int rc632_wait_idle_timer(void) +{ + u_int8_t irq, cmd; + + while (1) { + irq = rc632_reg_read(RC632_REG_INTERRUPT_RQ); + + /* FIXME: currently we're lazy: If we actually received + * something even after the timer expired, we accept it */ + if (irq & RC632_IRQ_TIMER && !(irq & RC632_IRQ_RX)) { + u_int8_t foo; + foo = rc632_reg_read(RC632_REG_PRIMARY_STATUS); + if (foo & 0x04) + foo = rc632_reg_read(RC632_REG_ERROR_FLAG); + + return -110; + } + + cmd = rc632_reg_read(RC632_REG_COMMAND); + + if (cmd == 0) + return 0; + + /* poll every millisecond */ + // usleep(1000); + } +} + + +static int +rc632_iso14443a_init(void) +{ // FIXME: some fifo work (drain fifo?) /* flush fifo (our way) */ - ret = rc632_reg_write(RC632_REG_CONTROL, 0x01); + rc632_reg_write(RC632_REG_CONTROL, 0x01); - ret = rc632_reg_write(RC632_REG_TX_CONTROL, + rc632_reg_write(RC632_REG_TX_CONTROL, (RC632_TXCTRL_TX1_RF_EN | RC632_TXCTRL_TX2_RF_EN | RC632_TXCTRL_TX2_INV | RC632_TXCTRL_FORCE_100_ASK | RC632_TXCTRL_MOD_SRC_INT)); - if (ret < 0) - return ret; - ret = rc632_reg_write(RC632_REG_CW_CONDUCTANCE, - CM5121_CW_CONDUCTANCE); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_CW_CONDUCTANCE, + OPENPCD_CW_CONDUCTANCE); /* Since FORCE_100_ASK is set (cf mc073930.pdf), this line may be left out? */ - ret = rc632_reg_write(RC632_REG_MOD_CONDUCTANCE, - CM5121_MOD_CONDUCTANCE); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_MOD_CONDUCTANCE, + OPENPCD_MOD_CONDUCTANCE); - ret = rc632_reg_write(RC632_REG_CODER_CONTROL, - (RC632_CDRCTRL_TXCD_14443A | - RC632_CDRCTRL_RATE_106K)); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_CODER_CONTROL, + (RC632_CDRCTRL_TXCD_14443A | + RC632_CDRCTRL_RATE_106K)); - ret = rc632_reg_write(RC632_REG_MOD_WIDTH, 0x13); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_MOD_WIDTH, 0x13); - ret = rc632_reg_write(RC632_REG_MOD_WIDTH_SOF, 0x3f); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_MOD_WIDTH_SOF, 0x3f); - ret = rc632_reg_write(RC632_REG_TYPE_B_FRAMING, 0x00); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_TYPE_B_FRAMING, 0x00); - ret = rc632_reg_write(RC632_REG_RX_CONTROL1, - (RC632_RXCTRL1_GAIN_35DB | - RC632_RXCTRL1_ISO14443 | - RC632_RXCTRL1_SUBCP_8)); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_RX_CONTROL1, + (RC632_RXCTRL1_GAIN_35DB | + RC632_RXCTRL1_ISO14443 | + RC632_RXCTRL1_SUBCP_8)); - ret = rc632_reg_write(RC632_REG_DECODER_CONTROL, - (RC632_DECCTRL_MANCHESTER | - RC632_DECCTRL_RXFR_14443A)); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_DECODER_CONTROL, + (RC632_DECCTRL_MANCHESTER | + RC632_DECCTRL_RXFR_14443A)); - ret = rc632_reg_write(RC632_REG_BIT_PHASE, - CM5121_14443A_BITPHASE); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_BIT_PHASE, + OPENPCD_14443A_BITPHASE); - ret = rc632_reg_write(RC632_REG_RX_THRESHOLD, - CM5121_14443A_THRESHOLD); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_RX_THRESHOLD, + OPENPCD_14443A_THRESHOLD); - ret = rc632_reg_write(RC632_REG_BPSK_DEM_CONTROL, 0x00); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_BPSK_DEM_CONTROL, 0x00); - ret = rc632_reg_write(RC632_REG_RX_CONTROL2, - (RC632_RXCTRL2_DECSRC_INT | - RC632_RXCTRL2_CLK_Q)); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_RX_CONTROL2, + (RC632_RXCTRL2_DECSRC_INT | + RC632_RXCTRL2_CLK_Q)); /* Omnikey proprietary driver has 0x03, but 0x06 is the default reset * value ?!? */ - ret = rc632_reg_write(RC632_REG_RX_WAIT, 0x06); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_RX_WAIT, 0x06); - ret = rc632_reg_write(RC632_REG_CHANNEL_REDUNDANCY, - (RC632_CR_PARITY_ENABLE | - RC632_CR_PARITY_ODD)); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); - ret = rc632_reg_write(RC632_REG_CRC_PRESET_LSB, 0x63); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_CRC_PRESET_LSB, 0x63); - ret = rc632_reg_write(RC632_REG_CRC_PRESET_MSB, 0x63); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_CRC_PRESET_MSB, 0x63); return 0; } @@ -129,53 +203,43 @@ rc632_transceive(const u_int8_t *tx_buf, return ret; /* clear all interrupts */ - ret = rc632_reg_write(RC632_REG_INTERRUPT_RQ, 0x7f); + rc632_reg_write(RC632_REG_INTERRUPT_RQ, 0x7f); do { - ret = rc632_fifo_write(cur_tx_len, cur_tx_buf, 0x03); - if (ret < 0) - return ret; - - if (cur_tx_buf == tx_buf) { - ret = rc632_reg_write(RC632_REG_COMMAND, - RC632_CMD_TRANSCEIVE); - if (ret < 0) - return ret; - } + rc632_fifo_write(cur_tx_len, cur_tx_buf); + + if (cur_tx_buf == tx_buf) + rc632_reg_write(RC632_REG_COMMAND, + RC632_CMD_TRANSCEIVE); cur_tx_buf += cur_tx_len; if (cur_tx_buf < tx_buf + tx_len) { u_int8_t fifo_fill; - ret = rc632_reg_read(RC632_REG_FIFO_LENGTH, - &fifo_fill); - if (ret < 0) - return ret; + fifo_fill = rc632_reg_read(RC632_REG_FIFO_LENGTH); cur_tx_len = 64 - fifo_fill; - printf("refilling tx fifo with %u bytes\n", cur_tx_len); + DEBUGPCR("refilling tx fifo with %u bytes", cur_tx_len); } else cur_tx_len = 0; } while (cur_tx_len); - if (toggle == 1) - tcl_toggle_pcb(handle); + //if (toggle == 1) + //tcl_toggle_pcb(handle); - ret = rc632_wait_idle_timer(handle); + ret = rc632_wait_idle_timer(); if (ret < 0) return ret; - ret = rc632_reg_read(RC632_REG_FIFO_LENGTH, rx_len); - if (ret < 0) - return ret; + *rx_len = rc632_reg_read(RC632_REG_FIFO_LENGTH); if (*rx_len == 0) { u_int8_t tmp; DEBUGP("rx_len == 0\n"); - rc632_reg_read(RC632_REG_ERROR_FLAG, &tmp); - rc632_reg_read(RC632_REG_CHANNEL_REDUNDANCY, &tmp); + tmp = rc632_reg_read(RC632_REG_ERROR_FLAG); + tmp = rc632_reg_read(RC632_REG_CHANNEL_REDUNDANCY); return -1; } @@ -184,7 +248,7 @@ rc632_transceive(const u_int8_t *tx_buf, } /* issue a 14443-3 A PCD -> PICC command in a short frame, such as REQA, WUPA */ -static int +int rc632_iso14443a_transceive_sf(u_int8_t cmd, struct iso14443a_atqa *atqa) { @@ -197,26 +261,20 @@ rc632_iso14443a_transceive_sf(u_int8_t cmd, tx_buf[0] = cmd; /* transfer only 7 bits of last byte in frame */ - ret = rc632_reg_write(RC632_REG_BIT_FRAMING, 0x07); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_BIT_FRAMING, 0x07); - ret = rc632_clear_bits(RC632_REG_CONTROL, - RC632_CONTROL_CRYPTO1_ON); - if (ret < 0) - return ret; + rc632_clear_bits(RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); #if 0 ret = rc632_reg_write(RC632_REG_CHANNEL_REDUNDANCY, (RC632_CR_PARITY_ENABLE | RC632_CR_PARITY_ODD)); #else - ret = rc632_clear_bits(RC632_REG_CHANNEL_REDUNDANCY, - RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); + rc632_clear_bits(RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); #endif - if (ret < 0) - return ret; ret = rc632_transceive(tx_buf, sizeof(tx_buf), (u_int8_t *)atqa, &rx_len, @@ -227,9 +285,7 @@ rc632_iso14443a_transceive_sf(u_int8_t cmd, } /* switch back to normal 8bit last byte */ - ret = rc632_reg_write(RC632_REG_BIT_FRAMING, 0x00); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_BIT_FRAMING, 0x00); if (rx_len != 2) { DEBUGP("rx_len(%d) != 2\n", rx_len); @@ -241,8 +297,7 @@ rc632_iso14443a_transceive_sf(u_int8_t cmd, /* transceive regular frame */ static int -rc632_iso14443ab_transceive(struct rfid_asic_handle *handle, - unsigned int frametype, +rc632_iso14443ab_transceive(unsigned int frametype, const u_int8_t *tx_buf, unsigned int tx_len, u_int8_t *rx_buf, unsigned int *rx_len, u_int64_t timeout, unsigned int flags) @@ -272,17 +327,13 @@ rc632_iso14443ab_transceive(struct rfid_asic_handle *handle, return -EINVAL; break; } - ret = rc632_reg_write(RC632_REG_CHANNEL_REDUNDANCY, - channel_red); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_CHANNEL_REDUNDANCY, channel_red); ret = rc632_transceive(tx_buf, tx_len, rx_buf, &rxl, timeout, 0); *rx_len = rxl; if (ret < 0) return ret; - return 0; } @@ -328,10 +379,8 @@ rc632_iso14443a_transceive_acf(struct iso14443a_anticol_cmd *acf, //rx_align = 8 - tx_last_bits;/* rx frame complements tx */ /* set RxAlign and TxLastBits*/ - ret = rc632_reg_write(RC632_REG_BIT_FRAMING, - (rx_align << 4) | (tx_last_bits)); - if (ret < 0) - return ret; + rc632_reg_write(RC632_REG_BIT_FRAMING, + (rx_align << 4) | (tx_last_bits)); ret = rc632_transceive((u_int8_t *)acf, tx_bytes, rx_buf, &rx_len, 0x32, 0); @@ -346,15 +395,11 @@ rc632_iso14443a_transceive_acf(struct iso14443a_anticol_cmd *acf, memcpy(&acf->uid_bits[tx_bytes+1-2], &rx_buf[1], rx_len-1); /* determine whether there was a collission */ - ret = rc632_reg_read(RC632_REG_ERROR_FLAG, &error_flag); - if (ret < 0) - return ret; + error_flag = rc632_reg_read(RC632_REG_ERROR_FLAG); if (error_flag & RC632_ERR_FLAG_COL_ERR) { /* retrieve bit of collission */ - ret = rc632_reg_read(RC632_REG_COLL_POS, &boc); - if (ret < 0) - return ret; + boc = rc632_reg_read(RC632_REG_COLL_POS); /* bit of collission relative to start of part 1 of * anticollision frame (!) */ |