From d256545b2fd62d78910efcc6273c3b70abd3aa13 Mon Sep 17 00:00:00 2001 From: laforge Date: Tue, 12 Sep 2006 17:35:30 +0000 Subject: move to new directory git-svn-id: https://svn.openpcd.org:2342/trunk@191 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- firmware/src/pcd/main_analog.c | 85 ++ firmware/src/pcd/main_dumbreader.c | 63 ++ firmware/src/pcd/main_pwm.c | 257 ++++++ firmware/src/pcd/main_reqa.c | 265 ++++++ firmware/src/pcd/rc632.c | 624 +++++++++++++ firmware/src/pcd/rc632.h | 31 + firmware/src/pcd/rc632_highlevel.c | 1473 ++++++++++++++++++++++++++++++ firmware/src/pcd/rfid_layer2_iso14443a.c | 319 +++++++ 8 files changed, 3117 insertions(+) create mode 100644 firmware/src/pcd/main_analog.c create mode 100644 firmware/src/pcd/main_dumbreader.c create mode 100644 firmware/src/pcd/main_pwm.c create mode 100644 firmware/src/pcd/main_reqa.c create mode 100644 firmware/src/pcd/rc632.c create mode 100644 firmware/src/pcd/rc632.h create mode 100644 firmware/src/pcd/rc632_highlevel.c create mode 100644 firmware/src/pcd/rfid_layer2_iso14443a.c (limited to 'firmware/src/pcd') diff --git a/firmware/src/pcd/main_analog.c b/firmware/src/pcd/main_analog.c new file mode 100644 index 0000000..8ffa1d4 --- /dev/null +++ b/firmware/src/pcd/main_analog.c @@ -0,0 +1,85 @@ +/* main_reqa - OpenPCD firmware for generating an endless loop of + * ISO 14443-A REQA packets. + * + * If a response is received from the PICC, LED1 (Red) will be switched + * on. If no valid response has been received within the timeout of the + * receiver, LED1 (Red) will be switched off. + * + */ + +#include +#include +#include +#include "rc632.h" +#include +#include +#include +#include +#include + +void _init_func(void) +{ + trigger_init(); + rc632_init(); + DEBUGPCRF("turning on RF"); + rc632_turn_on_rf(RAH); + /* FIXME: do we need this? */ + DEBUGPCRF("initializing 14443A operation"); + rc632_iso14443a_init(RAH); + /* Switch to 848kBps (1subcp / bit) */ + //rc632_clear_bits(RAH, RC632_REG_RX_CONTROL1, RC632_RXCTRL1_SUBCP_MASK); +} + +int _main_dbgu(char key) +{ + static char ana_out_sel; + int ret = -EINVAL; + + switch (key) { + case 'q': + ana_out_sel--; + ret = 1; + break; + case 'w': + ana_out_sel++; + ret = 1; + break; + case 'c': + rc632_turn_on_rf(RAH); + break; + case 'o': + rc632_turn_off_rf(RAH); + break; + } + + if (ana_out_sel >= 0xd) + ana_out_sel = 0; + + if (ret == 1) { + ana_out_sel &= 0x0f; + DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); + rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); + } + + return ret; +} + +void _main_func(void) +{ +#if 1 + struct iso14443a_atqa atqa; + + memset(&atqa, 0, sizeof(atqa)); + + trigger_pulse(); + + if (rc632_iso14443a_transceive_sf(RAH, ISO14443A_SF_CMD_WUPA, &atqa) < 0) { + DEBUGPCRF("error during transceive_sf"); + led_switch(1, 0); + } else { + DEBUGPCRF("received ATQA: %s\n", hexdump((char *)&atqa, sizeof(atqa))); + led_switch(1, 1); + } +#endif + led_toggle(2); +} diff --git a/firmware/src/pcd/main_dumbreader.c b/firmware/src/pcd/main_dumbreader.c new file mode 100644 index 0000000..1535e27 --- /dev/null +++ b/firmware/src/pcd/main_dumbreader.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include "rc632.h" +#include +#include +#include +#include "../openpcd.h" +#include + +void _init_func(void) +{ + rc632_init(); + rc632_test(RAH); +} + +int _main_dbgu(char key) +{ + unsigned char value; + + switch (key) { + case '4': + AT91F_DBGU_Printk("Testing RC632 : "); + if (rc632_test(RAH) == 0) + AT91F_DBGU_Printk("SUCCESS!\n\r"); + else + AT91F_DBGU_Printk("ERROR!\n\r"); + + break; + case '5': + rc632_reg_read(RAH, RC632_REG_RX_WAIT, &value); + DEBUGPCR("Reading RC632 Reg RxWait: 0x%02xr", value); + + break; + case '6': + DEBUGPCR("Writing RC632 Reg RxWait: 0x55"); + rc632_reg_write(RAH, RC632_REG_RX_WAIT, 0x55); + break; + case '7': + rc632_dump(); + break; + case 'P': + rc632_power(1); + break; + case 'p': + rc632_power(0); + 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 reqyests from USB EP1 (OUT) */ + usb_in_process(); + + rc632_unthrottle(); +} diff --git a/firmware/src/pcd/main_pwm.c b/firmware/src/pcd/main_pwm.c new file mode 100644 index 0000000..2f92d28 --- /dev/null +++ b/firmware/src/pcd/main_pwm.c @@ -0,0 +1,257 @@ +/* main_pwm - OpenPCD firmware for generating a PWM-modulated 13.56MHz + * carrier + * + * To use this, you need to connect PIOA P0 with MFIN of the reader. + */ + +#include +#include +#include +#include "../openpcd.h" +#include +#include +#include +#include +#include +#include +#include + +#ifdef SSC +#include +#endif + +static u_int8_t force_100ask = 1; +static u_int8_t mod_conductance = 0x3f; +static u_int8_t cw_conductance = 0x3f; +static u_int16_t duty_percent = 22; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +static u_int32_t pwm_freq[] = { 105937, 211875, 423750, 847500 }; +static u_int8_t pwm_freq_idx = 0; + +static void rc632_modulate_mfin() +{ + rc632_reg_write(RAH, RC632_REG_TX_CONTROL, + RC632_TXCTRL_MOD_SRC_MFIN|RC632_TXCTRL_TX2_INV| + RC632_TXCTRL_TX1_RF_EN|RC632_TXCTRL_TX2_RF_EN); +} + +/* (77/40) ^ EXPcsCfgCW */ +/* 1, 1.925, 3.705625, 7.13332812 */ + +#define COND_MANT(x) (x & 0x0f) +#define COND_EXP(x) ((x & 0x30) >> 4) + +static const u_int16_t rsrel_expfact[] = { 1000, 1925, 3706, 7133 }; + +static u_int32_t calc_conduct_rel(u_int8_t inp) +{ + u_int32_t cond_rel; + + cond_rel = COND_MANT(inp) * rsrel_expfact[COND_EXP(inp)]; + cond_rel = cond_rel / 1000; + + return cond_rel; +} + +static const u_int8_t rsrel_table[] = { + 0, 16, 32, 48, 1, 17, 2, 3, 33, 18, 4, 5, 19, 6, 7, 49, 34, 20, + 8, 9, 21, 10, 11, 35, 22, 12, 13, 23, 14, 50, 36, 15, 24, 25, + 37, 26, 27, 51, 38, 28, 29, 39, 30, 52, 31, 40, 41, 53, 42, 43, + 54, 44, 45, 55, 46, 47, 56, 57, 58, 59, 60, 61, 62, 63 }; + + +static const u_int16_t cdivs[] = { 128, 64, 32, 16 }; +static int cdiv_idx = 0; + +static void help(void) +{ + DEBUGPCR("o: decrease duty p: increase duty\r\n" + "k: stop pwm l: start pwn\r\n" + "n: decrease freq m: incresae freq\r\n" + "v: decrease mod_cond b: increase mod_cond\r\n" + "g: decrease cw_cond h: increase cw_cond"); + DEBUGPCR("u: PA23 const 1 y: PA23 const 0\r\n" + "t: PA23 PWM0 f: toggle Force100ASK\r\n" + "{: decrease cdiv_idx }: increse cdiv idx"); +} + +void _init_func(void) +{ + DEBUGPCR("\r\n===> main_pwm <===\r\n"); + help(); + + rc632_init(); + DEBUGPCRF("turning on RF"); + rc632_turn_on_rf(RAH); + + /* switch PA17 (connected to MFIN on board) to input */ + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, AT91C_PIO_PA17); + + DEBUGPCRF("Initializing carrier divider"); + tc_cdiv_init(); + + DEBUGPCRF("Initializing PWM"); + pwm_init(); + pwm_freq_set(0, 105937); + pwm_start(0); + pwm_duty_set_percent(0, 22); /* 22% of 9.43uS = 2.07uS */ + rc632_modulate_mfin(); + +#ifdef SSC + DEBUGPCRF("Initializing SSC RX"); + ssc_rx_init(); +#endif +} + +int _main_dbgu(char key) +{ + switch (key) { + case 'o': + if (duty_percent >= 1) + duty_percent--; + pwm_duty_set_percent(0, duty_percent); + break; + case 'p': + if (duty_percent <= 99) + duty_percent++; + pwm_duty_set_percent(0, duty_percent); + break; + case 'k': + pwm_stop(0); + break; + case 'l': + pwm_start(0); + break; + case 'n': + if (pwm_freq_idx > 0) { + pwm_freq_idx--; + pwm_stop(0); + pwm_freq_set(0, pwm_freq[pwm_freq_idx]); + pwm_start(0); + pwm_duty_set_percent(0, 22); /* 22% of 9.43uS = 2.07uS */ + } + break; + case 'm': + if (pwm_freq_idx < ARRAY_SIZE(pwm_freq)-1) { + pwm_freq_idx++; + pwm_stop(0); + pwm_freq_set(0, pwm_freq[pwm_freq_idx]); + pwm_start(0); + pwm_duty_set_percent(0, 22); /* 22% of 9.43uS = 2.07uS */ + } + break; + case 'u': + DEBUGPCRF("PA23 output high"); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); + break; + case 'y': + DEBUGPCRF("PA23 output low"); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA23); + return 0; + break; + case 't': + DEBUGPCRF("PA23 PeriphA (PWM)"); + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, AT91C_PA23_PWM0); + return 0; + break; + case 'f': + DEBUGPCRF("%sabling Force100ASK", force_100ask ? "Dis":"En"); + if (force_100ask) { + force_100ask = 0; + rc632_clear_bits(RAH, RC632_REG_TX_CONTROL, + RC632_TXCTRL_FORCE_100_ASK); + } else { + force_100ask = 1; + rc632_set_bits(RAH, RC632_REG_TX_CONTROL, + RC632_TXCTRL_FORCE_100_ASK); + } + return 0; + break; + case 'v': + if (mod_conductance > 0) { + mod_conductance--; + rc632_reg_write(RAH, RC632_REG_MOD_CONDUCTANCE, + rsrel_table[mod_conductance]); + } + break; + case 'b': + if (mod_conductance < 0x3f) { + mod_conductance++; + rc632_reg_write(RAH, RC632_REG_MOD_CONDUCTANCE, + rsrel_table[mod_conductance]); + } + break; + case 'g': + if (cw_conductance > 0) { + cw_conductance--; + rc632_reg_write(RAH, RC632_REG_CW_CONDUCTANCE, + rsrel_table[cw_conductance]); + } + break; + case 'h': + if (cw_conductance < 0x3f) { + cw_conductance++; + rc632_reg_write(RAH, RC632_REG_CW_CONDUCTANCE, + rsrel_table[cw_conductance]); + } + break; + case '?': + help(); + return 0; + break; + case '<': + tc_cdiv_phase_inc(); + break; + case '>': + tc_cdiv_phase_dec(); + break; + case '{': + if (cdiv_idx > 0) + cdiv_idx--; + tc_cdiv_set_divider(cdivs[cdiv_idx]); + break; + case '}': + if (cdiv_idx < ARRAY_SIZE(cdivs)-1) + cdiv_idx++; + tc_cdiv_set_divider(cdivs[cdiv_idx]); + break; +#ifdef SSC + case 's': + ssc_rx_start(); + break; + case 'S': + ssc_rx_stop(); + break; +#endif + default: + return -EINVAL; + } + + DEBUGPCR("pwm_freq=%u, duty_percent=%u, mod_cond=%u, cw_cond=%u tc_cdiv=%u", + pwm_freq[pwm_freq_idx], duty_percent, mod_conductance, cw_conductance, + cdivs[cdiv_idx]); + + return 0; +} + + +void _main_func(void) +{ + /* first we try to get rid of pending to-be-sent stuff */ + usb_out_process(); + + /* next we deal with incoming reqyests from USB EP1 (OUT) */ + usb_in_process(); + + /* try unthrottling sources since we now are [more] likely to + * have empty request contexts */ + rc632_unthrottle(); +#ifdef SSC + ssc_rx_unthrottle(); +#endif + + led_toggle(2); +} diff --git a/firmware/src/pcd/main_reqa.c b/firmware/src/pcd/main_reqa.c new file mode 100644 index 0000000..e28fdff --- /dev/null +++ b/firmware/src/pcd/main_reqa.c @@ -0,0 +1,265 @@ +/* main_reqa - OpenPCD firmware for generating an endless loop of + * ISO 14443-A REQA packets. Alternatively we can send WUPA, or + * perform a full ISO14443A anti-collision loop. + * + * If a response is received from the PICC, LED1 (Red) will be switched + * on. If no valid response has been received within the timeout of the + * receiver, LED1 (Red) will be switched off. + * + */ + +#include +#include +#include +#include +#include "rc632.h" +#include +#include +#include +#include + +#include "../openpcd.h" + +#ifdef WITH_TC +#include "tc.h" +#endif + +void _init_func(void) +{ + trigger_init(); + DEBUGPCRF("enabling RC632"); + rc632_init(); +#ifdef WITH_TC + DEBUGPCRF("enabling TC"); + tc_cdiv_init(); +#endif + DEBUGPCRF("turning on RF"); + rc632_turn_on_rf(RAH); + DEBUGPCRF("initializing 14443A operation"); + rc632_iso14443a_init(RAH); +} + +#define MODE_REQA 0x01 +#define MODE_WUPA 0x02 +#define MODE_ANTICOL 0x03 +#define MODE_14443A 0x04 + +static volatile int mode = MODE_REQA; + +static const char frame_14443a[] = { 0x00, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; + +static void reg_inc(u_int8_t reg) +{ + u_int8_t val; + rc632_reg_read(RAH, reg, &val); + rc632_reg_write(RAH, reg, val++); + DEBUGPCRF("reg 0x%02x = 0x%02x", reg, val); +} + +static void reg_dec(u_int8_t reg) +{ + u_int8_t val; + rc632_reg_read(RAH, reg, &val); + rc632_reg_write(RAH, reg, val--); + DEBUGPCRF("reg 0x%02x = 0x%02x", reg, val); +} + +static u_int8_t ana_out_sel; +static u_int8_t mfout_sel; +static u_int8_t speed_idx; + +static void help(void) +{ + DEBUGPCR("r: REQA w: WUPA a: ANTICOL\r\n" + "A: 14443A +: inc speed -: dec speed\r\n" + "y: inc cw cond x: dec cond c: inc mod cond"); + DEBUGPCR("v: dec mod cond o: dec ana_out p: dec ana_out\r\n" + "h: trigger high l: trigger low u: dec MFOUT mode"); + DEBUGPCR("i: inc MFOUT md <: dec cdiv ph >: inc cdiv phase\r\n" + "{: dev cdiv }: inc cdiv"); +} + +static u_int16_t cdivs[] = { 128, 64, 32, 16 }; + +int _main_dbgu(char key) +{ + int ret = 0; + static int cdiv_idx = 0; + + switch (key) { + case '?': + help(); + break; + case 'r': + mode = MODE_REQA; + break; + case 'w': + mode = MODE_WUPA; + break; + case 'A': + mode = MODE_14443A; + break; + case 'a': + mode = MODE_ANTICOL; + break; + /* Those below don't work as long as + * iso14443a_init() is called before + * every cycle */ + case 'y': + reg_inc(RC632_REG_CW_CONDUCTANCE); + break; + case 'x': + reg_dec(RC632_REG_CW_CONDUCTANCE); + break; + case 'c': + reg_inc(RC632_REG_MOD_CONDUCTANCE); + break; + case 'v': + reg_dec(RC632_REG_MOD_CONDUCTANCE); + break; + case 'o': + if (ana_out_sel > 0) { + ana_out_sel--; + DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); + rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); + } + ret = 1; + break; + case 'p': + if (ana_out_sel < 0xc) { + ana_out_sel++; + DEBUGPCR("switching to analog output mode 0x%x\n", ana_out_sel); + rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); + } + ret = 1; + break; + case 'u': + if (mfout_sel > 0) { + mfout_sel--; + DEBUGPCR("switching to MFOUT mode 0x%x\n", mfout_sel); + rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); + } + ret = 1; + break; + case 'i': + if (mfout_sel < 5) { + mfout_sel++; + DEBUGPCR("switching to MFOUT mode 0x%x\n", mfout_sel); + rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); + } + ret = 1; + break; + case 'h': + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); + break; + case 'l': + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_TRIGGER); + break; +#ifdef WITH_TC + case '<': + tc_cdiv_phase_inc(); + break; + case '>': + tc_cdiv_phase_dec(); + break; + case '{': + if (cdiv_idx > 0) + cdiv_idx--; + tc_cdiv_set_divider(cdivs[cdiv_idx]); + break; + case '}': + if (cdiv_idx < ARRAY_SIZE(cdivs)-1) + cdiv_idx++; + tc_cdiv_set_divider(cdivs[cdiv_idx]); + break; +#endif + case '-': + if (speed_idx > 0) + speed_idx--; + break; + case '+': + if (speed_idx < 3) + speed_idx++; + break; + default: + return -EINVAL; + } + + return ret; +} + +void _main_func(void) +{ + int status; + struct iso14443a_atqa atqa; + struct rfid_layer2_handle l2h; + volatile int i; + + memset(&atqa, 0, sizeof(atqa)); + + /* fake layer2 handle initialization */ + memset(&l2h, 0, sizeof(l2h)); + l2h.l2 = &rfid_layer2_iso14443a; + l2h.priv.iso14443a.state = ISO14443A_STATE_NONE; + l2h.priv.iso14443a.level = ISO14443A_LEVEL_NONE; + + /* FIXME: why does this only work every second attempt without reset or + * power-cycle? */ + rc632_turn_off_rf(); + //rc632_reset(); + rc632_turn_on_rf(); + + rc632_iso14443a_init(RAH); + rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, ana_out_sel); + rc632_reg_write(RAH, RC632_REG_MFOUT_SELECT, mfout_sel); + for (i = 0; i < 0x3ffff; i++) {} + //rc632_dump(); +#ifdef WITH_TC + tc_cdiv_print(); +#endif + + switch (mode) { + case MODE_REQA: + status = rc632_iso14443a_transceive_sf(RAH, ISO14443A_SF_CMD_REQA, &atqa); + if (status < 0) + DEBUGPCRF("error during transceive_sf REQA"); + else + DEBUGPCRF("received ATQA: %s", hexdump((char *)&atqa, sizeof(atqa))); + break; + case MODE_WUPA: + status = rc632_iso14443a_transceive_sf(RAH, ISO14443A_SF_CMD_WUPA, &atqa); + if (status < 0) + DEBUGPCRF("error during transceive_sf WUPA"); + else + DEBUGPCRF("received WUPA: %s", hexdump((char *)&atqa, sizeof(atqa))); + break; + case MODE_ANTICOL: + status = rfid_layer2_iso14443a.fn.open(&l2h); + if (status < 0) + DEBUGPCR("error during anticol"); + else + DEBUGPCR("Anticol OK"); + break; + case MODE_14443A: + { + char rx_buf[4]; + int rx_len = sizeof(rx_buf); + rfid_layer2_iso14443a.fn.setopt(&l2h, RFID_OPT_14443A_SPEED_RX, + &speed_idx, sizeof(speed_idx)); + rfid_layer2_iso14443a.fn.setopt(&l2h, RFID_OPT_14443A_SPEED_TX, + &speed_idx, sizeof(speed_idx)); + rfid_layer2_iso14443a.fn.transceive(&l2h, RFID_14443A_FRAME_REGULAR, + &frame_14443a, sizeof(frame_14443a), + &rx_buf, &rx_len, 1, 0); + } + break; + } + + if (status < 0) + led_switch(1, 0); + else + led_switch(1, 1); + + led_toggle(2); + +} diff --git a/firmware/src/pcd/rc632.c b/firmware/src/pcd/rc632.c new file mode 100644 index 0000000..5d45955 --- /dev/null +++ b/firmware/src/pcd/rc632.c @@ -0,0 +1,624 @@ +/* Philips CL RC632 driver (via SPI) for OpenPCD firmware + * (C) 2006 by Harald Welte + * + * This is heavily based on the librfid RC632 driver. All primitive access + * functions such as rc632_{reg,fifo}_{read,write}() are API compatible to + * librfid in order to be able to leverage higher-level code from librfid + * to this OpenPCD firmware. + * + * */ + +#include +#include +#include +#include +#include +#include "../openpcd.h" +#include +#include +#include +#include +#include +#include "rc632.h" + +#define ALWAYS_RESPOND + +#define NOTHING do {} while(0) + +#if 0 +#define DEBUGPSPI DEBUGP +#define DEBUGPSPIIRQ DEBUGP +#else +#define DEBUGPSPI(x, args ...) NOTHING +#define DEBUGPSPIIRQ(x, args...) NOTHING +#endif + +#if 0 +#define DEBUG632 DEBUGPCRF +#else +#define DEBUG632(x, args ...) NOTHING +#endif + + +/* SPI driver */ + +#ifdef OLIMEX +#define SPI_DEBUG_LOOPBACK +#endif + +#define SPI_USES_DMA + +#define SPI_MAX_XFER_LEN 65 + +static const AT91PS_SPI pSPI = AT91C_BASE_SPI; + +/* SPI irq handler */ +static void spi_irq(void) +{ + u_int32_t status = pSPI->SPI_SR; + + DEBUGPSPIIRQ("spi_irq: 0x%08x ", status); + + if (status & AT91C_SPI_OVRES) + DEBUGPSPIIRQ("Overrun "); + if (status & AT91C_SPI_MODF) + DEBUGPSPIIRQ("ModeFault "); + if (status & AT91C_SPI_ENDRX) { + pSPI->SPI_IDR = AT91C_SPI_ENDRX; + DEBUGPSPIIRQ("ENDRX "); + } + if (status & AT91C_SPI_ENDTX) { + pSPI->SPI_IDR = AT91C_SPI_ENDTX; + DEBUGPSPIIRQ("ENDTX "); + } + + DEBUGPSPIIRQ("\r\n"); + + AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_SPI); +} + +#ifdef SPI_USES_DMA +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) +{ + //tx_len = *rx_len = 65; + DEBUGPSPI("DMA Xfer tx=%s\r\n", hexdump(tx_data, tx_len)); + if (*rx_len < tx_len) { + DEBUGPCRF("rx_len=%u smaller tx_len=%u\n", *rx_len, tx_len); + return -1; + } + //AT91F_SPI_Disable(pSPI); + + AT91F_SPI_ReceiveFrame(pSPI, rx_data, tx_len, NULL, 0); + AT91F_SPI_SendFrame(pSPI, tx_data, tx_len, NULL, 0); + + AT91F_PDC_EnableRx(AT91C_BASE_PDC_SPI); + AT91F_PDC_EnableTx(AT91C_BASE_PDC_SPI); + + pSPI->SPI_IER = AT91C_SPI_ENDTX|AT91C_SPI_ENDRX; + //pSPI->SPI_IDR = AT91C_SPI_ENDTX|AT91C_SPI_ENDRX; + + + while (! (pSPI->SPI_SR & AT91C_SPI_ENDRX)) ; + + DEBUGPSPI("DMA Xfer finished rx=%s\r\n", hexdump(rx_data, tx_len)); + + *rx_len = tx_len; + + return 0; +} +#else +/* stupid polling transceiver routine */ +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; + + /* disable RC632 interrupt because it wants to do SPI transactions */ + AT91F_AIC_DisableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); + + 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"); + + /* Re-enable RC632 interrupts */ + AT91F_AIC_EnableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); + + return 0; +} +#endif + +/* RC632 driver */ + +/* static buffers used by RC632 access primitives below. + * Since we only have one */ + +static u_int8_t spi_outbuf[SPI_MAX_XFER_LEN]; +static u_int8_t spi_inbuf[SPI_MAX_XFER_LEN]; + +#define FIFO_ADDR (RC632_REG_FIFO_DATA << 1) + +struct rc632 { + u_int16_t flags; + struct fifo fifo; +}; +#define RC632_F_FIFO_TX 0x0001 +static struct rc632 rc632; + +/* RC632 access primitives */ + +int rc632_reg_write(struct rfid_asic_handle *hdl, + u_int8_t addr, u_int8_t data) +{ + u_int16_t rx_len = 2; + + DEBUG632("[0x%02x] <= 0x%02x", addr, data); + + addr = (addr << 1) & 0x7e; + + spi_outbuf[0] = addr; + spi_outbuf[1] = data; + + //spi_transceive(spi_outbuf, 2, NULL, NULL); + return spi_transceive(spi_outbuf, 2, spi_inbuf, &rx_len); +} + +int rc632_fifo_write(struct rfid_asic_handle *hdl, + u_int8_t len, u_int8_t *data, u_int8_t flags) +{ + if (len > sizeof(spi_outbuf)-1) + len = sizeof(spi_outbuf)-1; + + spi_outbuf[0] = FIFO_ADDR; + memcpy(&spi_outbuf[1], data, len); + + DEBUG632("[FIFO] <= %s", hexdump(data, len)); + + return spi_transceive(spi_outbuf, len+1, NULL, NULL); +} + +int rc632_reg_read(struct rfid_asic_handle *hdl, + u_int8_t addr, u_int8_t *val) +{ + u_int16_t rx_len = 2; + + addr = (addr << 1) & 0x7e; + + spi_outbuf[0] = addr | 0x80; + spi_outbuf[1] = 0x00; + + spi_transceive(spi_outbuf, 2, spi_inbuf, &rx_len); + *val = spi_inbuf[1]; + + DEBUG632("[0x%02x] => 0x%02x", addr>>1, *val); + + return 0; +} + +int rc632_fifo_read(struct rfid_asic_handle *hdl, + u_int8_t max_len, u_int8_t *data) +{ + int ret; + u_int8_t fifo_length; + u_int8_t i; + u_int16_t rx_len; + + ret = rc632_reg_read(hdl, RC632_REG_FIFO_LENGTH, &fifo_length); + if (ret < 0) + return ret; + + rx_len = fifo_length+1; + + if (max_len < fifo_length) + fifo_length = max_len; + + for (i = 0; i < fifo_length; i++) + spi_outbuf[i] = FIFO_ADDR; + + spi_outbuf[0] |= 0x80; + spi_outbuf[fifo_length] = 0x00; + + spi_transceive(spi_outbuf, fifo_length+1, spi_inbuf, &rx_len); + memcpy(data, spi_inbuf+1, rx_len-1); + + DEBUG632("[FIFO] => %s", hexdump(data, rx_len-1)); + + return 0; +} + +int rc632_set_bits(struct rfid_asic_handle *hdl, + u_int8_t reg, u_int8_t bits) +{ + u_int8_t val; + int ret; + + ret = rc632_reg_read(hdl, reg, &val); + if (ret < 0) + return ret; + + val |= bits; + + return rc632_reg_write(hdl, reg, val); +} + +int rc632_clear_bits(struct rfid_asic_handle *hdl, + u_int8_t reg, u_int8_t bits) +{ + u_int8_t val; + int ret; + + ret = rc632_reg_read(hdl, reg, &val); + if (ret < 0) + return ret; + + val &= ~bits; + + return rc632_reg_write(hdl, reg, val); +} + +/* RC632 interrupt handling */ + +static void rc632_irq(void) +{ + struct req_ctx *irq_rctx; + struct openpcd_hdr *irq_opcdh; + u_int8_t cause; + + /* CL RC632 has interrupted us */ + rc632_reg_read(RAH, RC632_REG_INTERRUPT_RQ, &cause); + + /* ACK all interrupts */ + //rc632_reg_write(RAH, RC632_REG_INTERRUPT_RQ, cause); + rc632_reg_write(RAH, RC632_REG_INTERRUPT_RQ, RC632_INT_TIMER); + DEBUGP("rc632_irq: "); + + if (cause & RC632_INT_LOALERT) { + /* FIFO is getting low, refill from virtual FIFO */ + DEBUGP("FIFO_low "); + #if 0 + if (!fifo_available(&rc632.fifo)) + return; + #endif + /* FIXME */ + } + if (cause & RC632_INT_HIALERT) { + /* FIFO is getting full, empty into virtual FIFO */ + DEBUGP("FIFO_high "); + /* FIXME */ + } + /* All interrupts below can be reported directly to the host */ + if (cause & RC632_INT_TIMER) + DEBUGP("Timer "); + if (cause & RC632_INT_IDLE) + DEBUGP("Idle "); + if (cause & RC632_INT_RX) + DEBUGP("RxComplete "); + if (cause & RC632_INT_TX) + DEBUGP("TxComplete "); + + + irq_rctx = req_ctx_find_get(RCTX_STATE_FREE, + RCTX_STATE_RC632IRQ_BUSY); + if (!irq_rctx) { + DEBUGPCRF("NO RCTX!\n"); + /* disable rc632 interrupt until RCTX is free */ + AT91F_AIC_DisableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); + return; + } + + irq_opcdh = (struct openpcd_hdr *) &irq_rctx->tx.data[0]; + + /* initialize static part of openpcd_hdr for USB IRQ reporting */ + irq_opcdh->cmd = OPENPCD_CMD_IRQ; + irq_opcdh->flags = 0x00; + irq_opcdh->reg = 0x07; + irq_opcdh->val = cause; + + req_ctx_set_state(irq_rctx, RCTX_STATE_UDP_EP3_PENDING); + DEBUGPCR(""); +} + +void rc632_unthrottle(void) +{ + AT91F_AIC_EnableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); +} + +void rc632_power(u_int8_t up) +{ + DEBUGPCRF("powering %s RC632", up ? "up" : "down"); + if (up) + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, + OPENPCD_PIO_RC632_RESET); + else + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, + OPENPCD_PIO_RC632_RESET); +} + +void rc632_reset(void) +{ + volatile int i; + + rc632_power(0); + for (i = 0; i < 0xffff; i++) + {} + rc632_power(1); + + /* wait for startup phase to finish */ + while (1) { + u_int8_t val; + rc632_reg_read(RAH, RC632_REG_COMMAND, &val); + if (val == 0x00) + break; + } + + /* turn off register paging */ + rc632_reg_write(RAH, RC632_REG_PAGE0, 0x00); +} + +static int rc632_usb_in(struct req_ctx *rctx) +{ + struct openpcd_hdr *poh = (struct openpcd_hdr *) &rctx->rx.data[0]; + struct openpcd_hdr *pih = (struct openpcd_hdr *) &rctx->tx.data[0]; + u_int16_t len = rctx->rx.tot_len-sizeof(*poh); + + switch (poh->cmd) { + case OPENPCD_CMD_READ_REG: + rc632_reg_read(RAH, poh->reg, &pih->val); + DEBUGP("READ REG(0x%02x)=0x%02x ", poh->reg, pih->val); + goto respond; + break; + case OPENPCD_CMD_READ_FIFO: + { + u_int16_t req_len = poh->val, remain_len = req_len, pih_len; + if (req_len > MAX_PAYLOAD_LEN) { + pih_len = MAX_PAYLOAD_LEN; + remain_len -= pih_len; + rc632_fifo_read(RAH, pih_len, pih->data); + rctx->tx.tot_len += pih_len; + DEBUGP("READ FIFO(len=%u)=%s ", req_len, + hexdump(pih->data, pih_len)); + req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); + udp_refill_ep(2, rctx); + + /* get and initialize second rctx */ + rctx = req_ctx_find_get(RCTX_STATE_FREE, + RCTX_STATE_MAIN_PROCESSING); + if (!rctx) { + DEBUGPCRF("FATAL_NO_RCTX!!!\n"); + break; + } + poh = (struct openpcd_hdr *) &rctx->rx.data[0]; + pih = (struct openpcd_hdr *) &rctx->tx.data[0]; + memcpy(pih, poh, sizeof(*poh)); + rctx->tx.tot_len = sizeof(*poh); + + pih_len = remain_len; + rc632_fifo_read(RAH, pih->val, pih->data); + rctx->tx.tot_len += pih_len; + DEBUGP("READ FIFO(len=%u)=%s ", pih_len, + hexdump(pih->data, pih_len)); + /* don't set state of second rctx, main function + * body will do this after switch statement */ + } else { + pih->val = poh->val; + rc632_fifo_read(RAH, poh->val, pih->data); + rctx->tx.tot_len += pih_len; + DEBUGP("READ FIFO(len=%u)=%s ", poh->val, + hexdump(pih->data, poh->val)); + } + goto respond; + break; + } + case OPENPCD_CMD_WRITE_REG: + DEBUGP("WRITE_REG(0x%02x, 0x%02x) ", poh->reg, poh->val); + rc632_reg_write(RAH, poh->reg, poh->val); + break; + case OPENPCD_CMD_WRITE_FIFO: + DEBUGP("WRITE FIFO(len=%u): %s ", len, + hexdump(poh->data, len)); + rc632_fifo_write(RAH, len, poh->data, 0); + break; + case OPENPCD_CMD_READ_VFIFO: + DEBUGP("READ VFIFO "); + DEBUGP("NOT IMPLEMENTED YET "); + goto respond; + break; + case OPENPCD_CMD_WRITE_VFIFO: + DEBUGP("WRITE VFIFO "); + DEBUGP("NOT IMPLEMENTED YET "); + break; + case OPENPCD_CMD_REG_BITS_CLEAR: + DEBUGP("CLEAR BITS "); + pih->val = rc632_clear_bits(RAH, poh->reg, poh->val); + break; + case OPENPCD_CMD_REG_BITS_SET: + DEBUGP("SET BITS "); + pih->val = rc632_set_bits(RAH, poh->reg, poh->val); + break; + case OPENPCD_CMD_DUMP_REGS: + DEBUGP("DUMP REGS "); + DEBUGP("NOT IMPLEMENTED YET "); + goto respond; + break; + default: + DEBUGP("UNKNOWN "); + return -EINVAL; + } + +#ifdef ALWAYS_RESPOND + goto respond; +#endif + + req_ctx_put(rctx); + DEBUGPCR(""); + return 0; + +respond: + req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); + /* FIXME: we could try to send this immediately */ + udp_refill_ep(2, rctx); + DEBUGPCR(""); + + return 1; +} + +void rc632_init(void) +{ + //fifo_init(&rc632.fifo, 256, NULL, &rc632); + + DEBUGPCRF("entering"); + + AT91F_SPI_CfgPMC(); + + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, + AT91C_PA11_NPCS0|AT91C_PA12_MISO| + AT91C_PA13_MOSI |AT91C_PA14_SPCK, 0); + + 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); + + AT91F_SPI_EnableIt(pSPI, AT91C_SPI_MODF|AT91C_SPI_OVRES); +#ifdef SPI_USES_DMA + AT91F_SPI_EnableIt(pSPI, AT91C_SPI_ENDRX|AT91C_SPI_ENDTX); +#endif + +#ifdef SPI_DEBUG_LOOPBACK + AT91F_SPI_CfgMode(pSPI, AT91C_SPI_MSTR|AT91C_SPI_PS_FIXED| + AT91C_SPI_MODFDIS|AT91C_SPI_LLB); +#else + AT91F_SPI_CfgMode(pSPI, AT91C_SPI_MSTR|AT91C_SPI_PS_FIXED| + AT91C_SPI_MODFDIS); +#endif + /* CPOL = 0, NCPHA = 1, CSAAT = 0, BITS = 0000, SCBR = 10 (4.8MHz), + * DLYBS = 0, DLYBCT = 0 */ +#ifdef SPI_USES_DMA + AT91F_SPI_CfgCs(pSPI, 0, AT91C_SPI_BITS_8|AT91C_SPI_NCPHA|(10<<8)); +#else + /* 320 kHz in case of I/O based SPI */ + AT91F_SPI_CfgCs(pSPI, 0, AT91C_SPI_BITS_8|AT91C_SPI_NCPHA|(0x7f<<8)); +#endif + AT91F_SPI_Enable(pSPI); + + /* Register rc632_irq */ + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632, + OPENPCD_IRQ_PRIO_RC632, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &rc632_irq); + AT91F_AIC_EnableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); + + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_RC632_RESET); + + rc632_reset(); + + /* configure IRQ pin */ + rc632_reg_write(RAH, RC632_REG_IRQ_PIN_CONFIG, + RC632_IRQCFG_CMOS|RC632_IRQCFG_INV); + /* enable interrupts */ + rc632_reg_write(RAH, RC632_REG_INTERRUPT_EN, RC632_INT_TIMER); + + /* configure AUX to test signal four */ + rc632_reg_write(RAH, RC632_REG_TEST_ANA_SELECT, 0x04); + + usb_hdlr_register(&rc632_usb_in, OPENPCD_CMD_CLS_RC632); +}; + +#if 0 +void rc632_exit(void) +{ + usb_hdlr_unregister(OPENPCD_CMD_CLS_RC632); + AT91F_AIC_DisableIt(AT91C_BASE_AIC, OPENPCD_IRQ_RC632); + AT91F_AIC_DisableIt(AT91C_BASE_AIC, AT91C_ID_SPI); + AT91F_SPI_Disable(pSPI); +} +#endif + +#ifdef DEBUG +static int rc632_reg_write_verify(struct rfid_asic_handle *hdl, + u_int8_t reg, u_int8_t val) +{ + u_int8_t tmp; + + rc632_reg_write(hdl, reg, val); + rc632_reg_read(hdl, reg, &tmp); + + DEBUGPCRF("reg=0x%02x, write=0x%02x, read=0x%02x ", reg, val, tmp); + + return (val == tmp); +} + +int rc632_dump(void) +{ + u_int8_t i; + u_int16_t rx_len = sizeof(spi_inbuf); + + for (i = 0; i <= 0x3f; i++) { + u_int8_t reg = i; + if (reg == RC632_REG_FIFO_DATA) + reg = 0x3e; + + spi_outbuf[i] = reg << 1; + spi_inbuf[i] = 0x00; + } + + /* MSB of first byte of read spi transfer is high */ + spi_outbuf[0] |= 0x80; + + /* last byte of read spi transfer is 0x00 */ + spi_outbuf[0x40] = 0x00; + spi_inbuf[0x40] = 0x00; + + spi_transceive(spi_outbuf, 0x41, spi_inbuf, &rx_len); + + for (i = 0; i < 0x3f; i++) { + if (i == RC632_REG_FIFO_DATA) + DEBUGPCR("REG 0x02 = NOT READ"); + else + DEBUGPCR("REG 0x%02x = 0x%02x", i, spi_inbuf[i+1]); + } + + return 0; +} + +int rc632_test(struct rfid_asic_handle *hdl) +{ + if (rc632_reg_write_verify(hdl, RC632_REG_RX_WAIT, 0x55) != 1) + return -1; + + if (rc632_reg_write_verify(hdl, RC632_REG_RX_WAIT, 0xAA) != 1) + return -1; + + return 0; +} +#else /* DEBUG */ +int rc632_test(struct rfid_asic_handle *hdl) {} +int rc632_dump(void) {} +#endif /* DEBUG */ diff --git a/firmware/src/pcd/rc632.h b/firmware/src/pcd/rc632.h new file mode 100644 index 0000000..1a4dc22 --- /dev/null +++ b/firmware/src/pcd/rc632.h @@ -0,0 +1,31 @@ +#ifndef _RC623_API_H +#define _RC632_API_H + +#include +#include +#include + +extern int rc632_reg_write(struct rfid_asic_handle *hdl, + u_int8_t addr, u_int8_t data); +extern int rc632_fifo_write(struct rfid_asic_handle *hdl, + u_int8_t len, u_int8_t *data, u_int8_t flags); +extern int rc632_reg_read(struct rfid_asic_handle *hdl, + u_int8_t addr, u_int8_t *val); +extern int rc632_fifo_read(struct rfid_asic_handle *hdl, + u_int8_t max_len, u_int8_t *data); +extern int rc632_clear_bits(struct rfid_asic_handle *hdl, + u_int8_t reg, u_int8_t bits); +extern int rc632_set_bits(struct rfid_asic_handle *hdl, + u_int8_t reg, u_int8_t bits); + +extern void rc632_init(void); +extern void rc632_exit(void); + +extern void rc632_unthrottle(void); + +#ifdef DEBUG +extern int rc632_test(struct rfid_asic_handle *hdl); +extern int rc632_dump(void); +#endif + +#endif diff --git a/firmware/src/pcd/rc632_highlevel.c b/firmware/src/pcd/rc632_highlevel.c new file mode 100644 index 0000000..b1186ab --- /dev/null +++ b/firmware/src/pcd/rc632_highlevel.c @@ -0,0 +1,1473 @@ +/* Generic Philips CL RC632 Routines + * + * (C) Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 +#include +#include +#include +#include "rc632.h" +#include +#include +#include + +/* 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 + +#define RC632_TMO_AUTH1 14000 + +#define RC632_TIMEOUT_FUZZ_FACTOR 10 + +#define USE_IRQ + +#define ENTER() DEBUGPCRF("entering") +struct rfid_asic rc632; + +static int +rc632_set_bit_mask(struct rfid_asic_handle *handle, + u_int8_t reg, u_int8_t mask, u_int8_t val) +{ + int ret; + u_int8_t tmp; + + ret = rc632_reg_read(handle, reg, &tmp); + if (ret < 0) + return ret; + + /* if bits are already like we want them, abort */ + if ((tmp & mask) == val) + return 0; + + return rc632_reg_write(handle, reg, (tmp & ~mask)|(val & mask)); +} + +int +rc632_turn_on_rf(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_set_bits(handle, RC632_REG_TX_CONTROL, 0x03); +} + +int +rc632_turn_off_rf(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_clear_bits(handle, RC632_REG_TX_CONTROL, 0x03); +} + +static int +rc632_power_up(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_POWERDOWN); +} + +static int +rc632_power_down(struct rfid_asic_handle *handle) +{ + return rc632_set_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_POWERDOWN); +} + +/* 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 best_presc, best_divisor, i; + int64_t smallest_diff; + + smallest_diff = 0x7fffffffffffffff; + best_presc = 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) { + best_presc = i; + best_divisor = tmp_div; + smallest_diff = diff; + } + } + + *prescaler = best_presc; + *divisor = best_divisor; + + DEBUGPCRF("timeout %u usec, prescaler = %u, divisor = %u", timeout, best_presc, best_divisor); + + return 0; +} + +static int +rc632_timer_set(struct rfid_asic_handle *handle, + u_int64_t timeout) +{ + int ret; + u_int8_t prescaler, divisor; + + ret = best_prescaler(timeout*RC632_TIMEOUT_FUZZ_FACTOR, + &prescaler, &divisor); + + ret = rc632_reg_write(handle, RC632_REG_TIMER_CLOCK, + prescaler & 0x1f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TIMER_CONTROL, + RC632_TMR_START_TX_END|RC632_TMR_STOP_RX_BEGIN); + + /* clear timer irq bit */ + ret |= rc632_set_bits(handle, RC632_REG_INTERRUPT_RQ, RC632_INT_TIMER); + +#ifdef USE_IRQ_ + /* enable interrupt for expired timer */ + ret |= rc632_reg_write(handle, RC632_REG_INTERRUPT_EN, + RC632_INT_TIMER|RC632_INT_SET); +#endif + + ret |= rc632_reg_write(handle, RC632_REG_TIMER_RELOAD, divisor); + + return ret; +} + +/* Wait until RC632 is idle or TIMER IRQ has happened */ +static int rc632_wait_idle_timer(struct rfid_asic_handle *handle) +{ + int ret; + u_int8_t irq, cmd; + + while (1) { + ret = rc632_reg_read(handle, RC632_REG_INTERRUPT_RQ, &irq); + if (ret < 0) + return ret; + + /* FIXME: currently we're lazy: If we actually received + * something even after the timer expired, we accept it */ + if (irq & RC632_INT_TIMER && !(irq & RC632_INT_RX)) { + u_int8_t foo; + rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &foo); + DEBUGPCRF("TIMER && !INT_RX, PRIM_STATUS=0x%02x", foo); + if (foo & 0x04) { + rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &foo); + DEBUGPCRF("ERROR_FLAG=0x%02x, returning timeout", foo); + } + + return -ETIMEDOUT; + } + + ret = rc632_reg_read(handle, RC632_REG_COMMAND, &cmd); + if (ret < 0) + return ret; + + if (cmd == 0 || irq & RC632_INT_RX) + return 0; + + /* poll every millisecond */ + /* FIXME usleep(1000);*/ + } +} + +/* Stupid RC632 implementations don't evaluate interrupts but poll the + * command register for "status idle" */ +static int +rc632_wait_idle(struct rfid_asic_handle *handle, u_int64_t timeout) +{ + u_int8_t cmd = 0xff; + int ret, cycles = 0; +#define USLEEP_PER_CYCLE 128 + + while (cmd != 0) { + ret = rc632_reg_read(handle, RC632_REG_COMMAND, &cmd); + if (ret < 0) + return ret; + + if (cmd == 0) { + /* FIXME: read second time ?? */ + return 0; + } + + { + u_int8_t foo; + rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &foo); + if (foo & 0x04) + rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &foo); + } + + /* Abort after some timeout */ + if (cycles > timeout*RC632_TIMEOUT_FUZZ_FACTOR/USLEEP_PER_CYCLE) { + return -ETIMEDOUT; + } + + cycles++; + usleep(USLEEP_PER_CYCLE); + } + + return 0; +} + +static int +rc632_transmit(struct rfid_asic_handle *handle, + const u_int8_t *buf, + u_int8_t len, + u_int64_t timeout) +{ + int ret, cur_len; + const u_int8_t *cur_buf = buf; + + if (len > 64) + cur_len = 64; + else + cur_len = len; + + do { + ret = rc632_fifo_write(handle, cur_len, cur_buf, 0x03); + if (ret < 0) + return ret; + + if (cur_buf == buf) { + /* only start transmit first time */ + ret = rc632_reg_write(handle, RC632_REG_COMMAND, + RC632_CMD_TRANSMIT); + if (ret < 0) + return ret; + } + + cur_buf += cur_len; + if (cur_buf < buf + len) { + cur_len = buf - cur_buf; + if (cur_len > 64) + cur_len = 64; + } else + cur_len = 0; + + } while (cur_len); + + return rc632_wait_idle(handle, timeout); +} + +static int +tcl_toggle_pcb(struct rfid_asic_handle *handle) +{ + // FIXME: toggle something between 0x0a and 0x0b + return 0; +} + +static int +rc632_transceive(struct rfid_asic_handle *handle, + const u_int8_t *tx_buf, + u_int8_t tx_len, + u_int8_t *rx_buf, + u_int8_t *rx_len, + u_int64_t timer, + unsigned int toggle) +{ + int ret, cur_tx_len; + const u_int8_t *cur_tx_buf = tx_buf; + + DEBUGPCRF("tx_len=%u, rx_len=%u, timer=%llu", tx_len, *rx_len, timer); + + if (tx_len > 64) + cur_tx_len = 64; + else + cur_tx_len = tx_len; + + ret = rc632_reg_write(handle, RC632_REG_COMMAND, 0x00); + /* clear all interrupts */ + ret = rc632_reg_write(handle, RC632_REG_INTERRUPT_RQ, 0x7f); + if (ret < 0) + return ret; + + ret = rc632_timer_set(handle, timer); + if (ret < 0) + return ret; + + do { + ret = rc632_fifo_write(handle, cur_tx_len, cur_tx_buf, 0x03); + if (ret < 0) + return ret; + + if (cur_tx_buf == tx_buf) { + ret = rc632_reg_write(handle, RC632_REG_COMMAND, + RC632_CMD_TRANSCEIVE); + if (ret < 0) + return ret; + } + + cur_tx_buf += cur_tx_len; + if (cur_tx_buf < tx_buf + tx_len) { + u_int8_t fifo_fill; + ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, + &fifo_fill); + if (ret < 0) + return ret; + + cur_tx_len = 64 - fifo_fill; + DEBUGPCRF("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); + + ret = rc632_wait_idle_timer(handle); + if (ret < 0) + return ret; + + ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, rx_len); + if (ret < 0) + return ret; + + DEBUGPCRF("rx_len = %u\n", *rx_len); + + if (*rx_len == 0) { + u_int8_t tmp, tmp2; + + rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &tmp); + rc632_reg_read(handle, RC632_REG_CHANNEL_REDUNDANCY, &tmp2); + + DEBUGPCRF("rx_len == 0, error_flag=0x%02x, channel_red=0x%02x", + tmp, tmp2); + + return -1; + } + + return rc632_fifo_read(handle, *rx_len, rx_buf); +} + +int +rc632_read_eeprom(struct rfid_asic_handle *handle, u_int16_t addr, u_int8_t len, + u_int8_t *recvbuf) +{ + u_int8_t sndbuf[3]; + u_int8_t err; + int ret; + + sndbuf[0] = (addr & 0xff); + sndbuf[1] = addr >> 8; + sndbuf[2] = len; + + ret = rc632_fifo_write(handle, 3, sndbuf, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_READ_E2); + if (ret < 0) + return ret; + + /* usleep(20000); */ + + ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &err); + if (err & RC632_ERR_FLAG_ACCESS_ERR) + return -EPERM; + + ret = rc632_reg_read(handle, RC632_REG_FIFO_DATA, &err); + if (err < len) + len = err; + + ret = rc632_fifo_read(handle, len, recvbuf); + if (ret < 0) + return ret; + + return len; +} + +static int +rc632_calc_crc16_from(struct rfid_asic_handle *handle) +{ + u_int8_t sndbuf[2] = { 0x01, 0x02 }; + u_int8_t crc_lsb = 0x00 , crc_msb = 0x00; + int ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x12); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0xe0); + if (ret < 0) + return ret; + + ret = rc632_fifo_write(handle, sizeof(sndbuf), sndbuf, 3); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_CALC_CRC); + if (ret < 0) + return ret; + + usleep(10000); // FIXME: no checking for cmd completion? + + ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_LSB, &crc_lsb); + if (ret < 0) + return ret; + + ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_MSB, &crc_msb); + if (ret < 0) + return ret; + + // FIXME: what to do with crc result? + return ret; +} + + +int +rc632_register_dump(struct rfid_asic_handle *handle, u_int8_t *buf) +{ + int ret; + u_int8_t i; + + for (i = 0; i <= 0x3f; i++) { + ret = rc632_reg_read(handle, i, &buf[i]); + // do we want error checks? + } + return 0; +} + + +#if 0 +static int +rc632_init(struct rfid_asic_handle *ah) +{ + int ret; + + /* switch off rf (make sure PICCs are reset at init time) */ + ret = rc632_power_down(ah); + if (ret < 0) + return ret; + + usleep(10000); + + /* switch on rf */ + ret = rc632_power_up(ah); + if (ret < 0) + return ret; + + /* disable register paging */ + ret = rc632_reg_write(ah, 0x00, 0x00); + if (ret < 0) + return ret; + + /* set some sane default values */ + ret = rc632_reg_write(ah, 0x11, 0x5b); + if (ret < 0) + return ret; + + /* switch on rf */ + ret = rc632_turn_on_rf(ah); + if (ret < 0) + return ret; + + return 0; +} + +static int +rc632_fini(struct rfid_asic_handle *ah) +{ + int ret; + + /* switch off rf */ + ret = rc632_turn_off_rf(ah); + if (ret < 0) + return ret; + + ret = rc632_power_down(ah); + if (ret < 0) + return ret; + + return 0; +} +#endif + + +/* + * Philips CL RC632 primitives for ISO 14443-A compliant PICC's + * + * (C) 2005 by Harald Welte + * + */ + +int +rc632_iso14443a_init(struct rfid_asic_handle *handle) +{ + int ret; + + // FIXME: some fifo work (drain fifo?) + + /* flush fifo (our way) */ + ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01); + + ret = rc632_reg_write(handle, 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(handle, RC632_REG_CW_CONDUCTANCE, + OPENPCD_CW_CONDUCTANCE); + if (ret < 0) + return ret; + + /* Since FORCE_100_ASK is set (cf mc073930.pdf), this line may be left out? */ + ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, + OPENPCD_MOD_CONDUCTANCE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL, + (RC632_CDRCTRL_TXCD_14443A | + RC632_CDRCTRL_RATE_106K)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, 0x00); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1, + (RC632_RXCTRL1_GAIN_35DB | + RC632_RXCTRL1_ISO14443 | + RC632_RXCTRL1_SUBCP_8)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL, + (RC632_DECCTRL_MANCHESTER | + RC632_DECCTRL_RXFR_14443A)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE, + OPENPCD_14443A_BITPHASE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, + OPENPCD_14443A_THRESHOLD); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, 0x00); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2, + (RC632_RXCTRL2_DECSRC_INT | + RC632_RXCTRL2_CLK_Q)); + if (ret < 0) + return ret; + + /* Omnikey proprietary driver has 0x03, but 0x06 is the default reset value ?!? */ + ret = rc632_reg_write(handle, RC632_REG_RX_WAIT, 0x06); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x63); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0x63); + if (ret < 0) + return ret; + + return 0; +} + +static int +rc632_iso14443a_fini(struct iso14443a_handle *handle_14443) +{ + +#if 0 + ret = rc632_turn_off_rf(handle); + if (ret < 0) + return ret; +#endif + + + return 0; +} + + +/* issue a 14443-3 A PCD -> PICC command in a short frame, such as REQA, WUPA */ +int +rc632_iso14443a_transceive_sf(struct rfid_asic_handle *handle, + u_int8_t cmd, + struct iso14443a_atqa *atqa) +{ + int ret; + u_int8_t tx_buf[1]; + u_int8_t rx_len = 2; + + DEBUGPCRF(""); + memset(atqa, 0, sizeof(atqa)); + + tx_buf[0] = cmd; + + /* transfer only 7 bits of last byte in frame */ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x07); + if (ret < 0) + return ret; + + ret = rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + if (ret < 0) + return ret; + +#if 0 + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); +#else + ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); + +#endif + if (ret < 0) + return ret; + + ret = rc632_transceive(handle, tx_buf, sizeof(tx_buf), + (u_int8_t *)atqa, &rx_len, + ISO14443A_FDT_ANTICOL_LAST1, 0); + if (ret < 0) { + DEBUGPCRF("error during rc632_transceive()"); + return ret; + } + + /* switch back to normal 8bit last byte */ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x00); + if (ret < 0) + return ret; + + if (rx_len != 2) { + DEBUGPCRF("rx_len(%d) != 2", rx_len); + return -1; + } + + return 0; +} + +/* transceive regular frame */ +int +rc632_iso14443ab_transceive(struct rfid_asic_handle *handle, + 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) +{ + int ret; + u_int8_t rxl = *rx_len & 0xff; + u_int8_t channel_red; + + DEBUGPCRF("tx_len=%u, rx_len=%u", tx_len, *rx_len); + + memset(rx_buf, 0, *rx_len); + + switch (frametype) { + case RFID_14443A_FRAME_REGULAR: + case RFID_MIFARE_FRAME: + channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE + |RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD; + break; + case RFID_14443B_FRAME_REGULAR: + channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE + |RC632_CR_CRC3309; + break; +#if 0 + case RFID_MIFARE_FRAME: + channel_red = RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD; + break; +#endif + default: + return -EINVAL; + break; + } + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + channel_red); + if (ret < 0) + return ret; + + ret = rc632_transceive(handle, tx_buf, tx_len, rx_buf, &rxl, timeout, 0); + *rx_len = rxl; + if (ret < 0) + return ret; + + + return 0; +} + +/* transceive anti collission bitframe */ +int +rc632_iso14443a_transceive_acf(struct rfid_asic_handle *handle, + struct iso14443a_anticol_cmd *acf, + unsigned int *bit_of_col) +{ + int ret; + u_int8_t rx_buf[64]; + u_int8_t rx_len = sizeof(rx_buf); + u_int8_t rx_align = 0, tx_last_bits, tx_bytes; + u_int8_t boc; + u_int8_t error_flag; + *bit_of_col = ISO14443A_BITOFCOL_NONE; + memset(rx_buf, 0, sizeof(rx_buf)); + + /* disable mifare cryto */ + ret = rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + if (ret < 0) + return ret; + + /* disable CRC summing */ +#if 0 + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); +#else + ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_TX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); +#endif + if (ret < 0) + return ret; + + tx_last_bits = acf->nvb & 0x0f; /* lower nibble indicates bits */ + tx_bytes = acf->nvb >> 4; + if (tx_last_bits) { + tx_bytes++; + rx_align = (tx_last_bits+1) % 8;/* rx frame complements tx */ + } + + //rx_align = 8 - tx_last_bits;/* rx frame complements tx */ + + /* set RxAlign and TxLastBits*/ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, + (rx_align << 4) | (tx_last_bits)); + if (ret < 0) + return ret; + + ret = rc632_transceive(handle, (u_int8_t *)acf, tx_bytes, + rx_buf, &rx_len, 0x32, 0); + if (ret < 0) + return ret; + + /* bitwise-OR the two halves of the split byte */ + acf->uid_bits[tx_bytes-2] = ( + (acf->uid_bits[tx_bytes-2] & (0xff >> (8-tx_last_bits))) + | rx_buf[0]); + /* copy the rest */ + memcpy(&acf->uid_bits[tx_bytes+1-2], &rx_buf[1], rx_len-1); + + /* determine whether there was a collission */ + ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &error_flag); + if (ret < 0) + return ret; + + if (error_flag & RC632_ERR_FLAG_COL_ERR) { + /* retrieve bit of collission */ + ret = rc632_reg_read(handle, RC632_REG_COLL_POS, &boc); + if (ret < 0) + return ret; + + /* bit of collission relative to start of part 1 of + * anticollision frame (!) */ + *bit_of_col = 2*8 + boc; + } + + return 0; +} + +enum rc632_rate { + RC632_RATE_106 = 0x00, + RC632_RATE_212 = 0x01, + RC632_RATE_424 = 0x02, + RC632_RATE_848 = 0x03, +}; + +struct rx_config { + u_int8_t subc_pulses; + u_int8_t rx_coding; + u_int8_t rx_threshold; + u_int8_t bpsk_dem_ctrl; +}; + +struct tx_config { + u_int8_t rate; + u_int8_t mod_width; +}; + +static const struct rx_config rx_configs[] = { + { + .subc_pulses = RC632_RXCTRL1_SUBCP_8, + .rx_coding = RC632_DECCTRL_MANCHESTER, + .rx_threshold = 0x88, + .bpsk_dem_ctrl = 0x00, + }, + { + .subc_pulses = RC632_RXCTRL1_SUBCP_4, + .rx_coding = RC632_DECCTRL_BPSK, + .rx_threshold = 0x50, + .bpsk_dem_ctrl = 0x0c, + }, + { + .subc_pulses = RC632_RXCTRL1_SUBCP_2, + .rx_coding = RC632_DECCTRL_BPSK, + .rx_threshold = 0x50, + .bpsk_dem_ctrl = 0x0c, + }, + { + .subc_pulses = RC632_RXCTRL1_SUBCP_1, + .rx_coding = RC632_DECCTRL_BPSK, + .rx_threshold = 0x50, + .bpsk_dem_ctrl = 0x0c, + }, +}; + +static const struct tx_config tx_configs[] = { + { + .rate = RC632_CDRCTRL_RATE_106K, + .mod_width = 0x13, + }, + { + .rate = RC632_CDRCTRL_RATE_212K, + .mod_width = 0x07, + }, + { + .rate = RC632_CDRCTRL_RATE_424K, + .mod_width = 0x03, + }, + { + .rate = RC632_CDRCTRL_RATE_848K, + .mod_width = 0x01, + }, +}; + +int rc632_iso14443a_set_speed(struct rfid_asic_handle *handle, + unsigned int tx, + u_int8_t rate) +{ + int rc; + u_int8_t reg; + + + if (!tx) { + /* Rx */ + if (rate > ARRAY_SIZE(rx_configs)) + return -EINVAL; + + rc = rc632_set_bit_mask(handle, RC632_REG_RX_CONTROL1, + RC632_RXCTRL1_SUBCP_MASK, + rx_configs[rate].subc_pulses); + if (rc < 0) + return rc; + + rc = rc632_set_bit_mask(handle, RC632_REG_DECODER_CONTROL, + RC632_DECCTRL_BPSK, + rx_configs[rate].rx_coding); + if (rc < 0) + return rc; + + rc = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, + rx_configs[rate].rx_threshold); + if (rc < 0) + return rc; + + if (rx_configs[rate].rx_coding == RC632_DECCTRL_BPSK) { + rc = rc632_reg_write(handle, + RC632_REG_BPSK_DEM_CONTROL, + rx_configs[rate].bpsk_dem_ctrl); + if (rc < 0) + return rc; + } + } else { + /* Tx */ + if (rate > ARRAY_SIZE(tx_configs)) + return -EINVAL; + + rc = rc632_set_bit_mask(handle, RC632_REG_CODER_CONTROL, + RC632_CDRCTRL_RATE_MASK, + tx_configs[rate].rate); + if (rc < 0) + return rc; + + rc = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, + tx_configs[rate].mod_width); + if (rc < 0) + return rc; + } + + return 0; +} + +static int rc632_iso14443b_init(struct rfid_asic_handle *handle) +{ + int ret; + + // FIXME: some FIFO work + + /* flush fifo (our way) */ + ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL, + (RC632_TXCTRL_TX1_RF_EN | + RC632_TXCTRL_TX2_RF_EN | + RC632_TXCTRL_TX2_INV | + RC632_TXCTRL_MOD_SRC_INT)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE, 0x3f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, 0x04); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL, + (RC632_CDRCTRL_TXCD_NRZ | + RC632_CDRCTRL_RATE_14443B)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, + (RC632_TBFRAMING_SOF_11L_3H | + (6 << RC632_TBFRAMING_SPACE_SHIFT) | + RC632_TBFRAMING_EOF_11)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1, + (RC632_RXCTRL1_GAIN_35DB | + RC632_RXCTRL1_ISO14443 | + RC632_RXCTRL1_SUBCP_8)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL, + (RC632_DECCTRL_BPSK | + RC632_DECCTRL_RXFR_14443B)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE, + OPENPCD_14443B_BITPHASE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, + OPENPCD_14443B_THRESHOLD); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, + ((0x2 & RC632_BPSKD_TAUB_MASK)<> 4; + key12[i * 2 + 1] = (~ln << 4) | ln; + key12[i * 2] = (~hn << 4) | hn; + } + return 0; +} + +static int +rc632_mifare_set_key(struct rfid_asic_handle *h, const u_int8_t *key) +{ + u_int8_t coded_key[RFID_MIFARE_KEY_CODED_LEN]; + u_int8_t reg; + int ret; + + ret = rc632_mifare_transform_key(key, coded_key); + if (ret < 0) + return ret; + + ret = rc632_fifo_write(h, RFID_MIFARE_KEY_CODED_LEN, coded_key, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_LOAD_KEY); + if (ret < 0) + return ret; + + ret = rc632_wait_idle(h, RC632_TMO_AUTH1); + if (ret < 0) + return ret; + + ret = rc632_reg_read(h, RC632_REG_ERROR_FLAG, ®); + if (ret < 0) + return ret; + + if (reg & RC632_ERR_FLAG_KEY_ERR) + return -EINVAL; + + return 0; +} + +static int +rc632_mifare_auth(struct rfid_asic_handle *h, u_int8_t cmd, u_int32_t serno, + u_int8_t block) +{ + int ret; + struct mifare_authcmd acmd; + u_int8_t reg; + + if (cmd != RFID_CMD_MIFARE_AUTH1A && cmd != RFID_CMD_MIFARE_AUTH1B) + return -EINVAL; + + /* Initialize acmd */ + acmd.block_address = block & 0xff; + acmd.auth_cmd = cmd; + //acmd.serno = htonl(serno); + acmd.serno = serno; + + /* Clear Rx CRC */ + ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_RX_CRC_ENABLE); + if (ret < 0) + return ret; + + /* Send Authent1 Command */ + ret = rc632_fifo_write(h, sizeof(acmd), (unsigned char *)&acmd, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT1); + if (ret < 0) + return ret; + + /* Wait until transmitter is idle */ + ret = rc632_wait_idle(h, RC632_TMO_AUTH1); + if (ret < 0) + return ret; + + ret = rc632_reg_read(h, RC632_REG_SECONDARY_STATUS, ®); + if (ret < 0) + return ret; + if (reg & 0x07) + return -EIO; + + /* Clear Tx CRC */ + ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_TX_CRC_ENABLE); + if (ret < 0) + return ret; + + /* Send Authent2 Command */ + ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT2); + if (ret < 0) + return ret; + + /* Wait until transmitter is idle */ + ret = rc632_wait_idle(h, RC632_TMO_AUTH1); + if (ret < 0) + return ret; + + /* Check whether authentication was successful */ + ret = rc632_reg_read(h, RC632_REG_CONTROL, ®); + if (ret < 0) + return ret; + + if (!(reg & RC632_CONTROL_CRYPTO1_ON)) + return -EACCES; + + return 0; + +} + +/* transceive regular frame */ +static int +rc632_mifare_transceive(struct rfid_asic_handle *handle, + 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) +{ + int ret; + u_int8_t rxl = *rx_len & 0xff; + + DEBUGP("entered\n"); + memset(rx_buf, 0, *rx_len); + +#if 1 + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD | + RC632_CR_TX_CRC_ENABLE | + RC632_CR_RX_CRC_ENABLE)); +#else + ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); +#endif + if (ret < 0) + return ret; + + ret = rc632_transceive(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0); + *rx_len = rxl; + if (ret < 0) + return ret; + + + return 0; +} + diff --git a/firmware/src/pcd/rfid_layer2_iso14443a.c b/firmware/src/pcd/rfid_layer2_iso14443a.c new file mode 100644 index 0000000..80d9d5f --- /dev/null +++ b/firmware/src/pcd/rfid_layer2_iso14443a.c @@ -0,0 +1,319 @@ +/* ISO 14443-3 A anticollision implementation + * + * (C) 2005 by Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 +#include +#include +#include + +#include +#include +//#include +#include + +#define TIMEOUT 1236 + +/* Transceive a 7-bit short frame */ +static int +iso14443a_transceive_sf(struct rfid_layer2_handle *handle, + unsigned char cmd, + struct iso14443a_atqa *atqa) +{ + //struct rfid_reader *rdr = handle->rh->reader; + DEBUGPCRF(""); + + return rc632_iso14443a_transceive_sf(handle->rh, cmd, atqa); +} + +/* Transmit an anticollission bit frame */ +static int +iso14443a_transceive_acf(struct rfid_layer2_handle *handle, + struct iso14443a_anticol_cmd *acf, + unsigned int *bit_of_col) +{ + //struct rfid_reader *rdr = handle->rh->reader; + DEBUGPCRF(""); + + return rc632_iso14443a_transceive_acf(handle->rh, acf, bit_of_col); +} + +/* Transmit a regular frame */ +static int +iso14443a_transceive(struct rfid_layer2_handle *handle, + enum rfid_frametype frametype, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + DEBUGPCRF("tx_len=%u, rx_len=%u", tx_len, *rx_len); + return rc632_iso14443ab_transceive(handle->rh, frametype, tx_buf, + tx_len, rx_buf, rx_len, timeout, flags); +} + +static int +iso14443a_code_nvb_bits(unsigned char *nvb, unsigned int bits) +{ + unsigned int byte_count = bits / 8; + unsigned int bit_count = bits % 8; + + if (byte_count < 2 || byte_count > 7) + return -1; + + *nvb = ((byte_count & 0xf) << 4) | bit_count; + + return 0; +} + +/* first bit is '1', second bit '2' */ +static void +set_bit_in_field(unsigned char *bitfield, unsigned int bit) +{ + unsigned int byte_count = bit / 8; + unsigned int bit_count = bit % 8; + + DEBUGP("bitfield=%p, byte_count=%u, bit_count=%u\n", + bitfield, byte_count, bit_count); + DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count)); + *(bitfield+byte_count) |= 1 << (bit_count-1); + DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count)); +} + +static int +iso14443a_anticol(struct rfid_layer2_handle *handle) +{ + int ret; + unsigned int uid_size; + struct iso14443a_handle *h = &handle->priv.iso14443a; + struct iso14443a_atqa atqa; + struct iso14443a_anticol_cmd acf; + unsigned int bit_of_col; + unsigned char sak[3]; + unsigned int rx_len = sizeof(sak); + char *aqptr = (char *) &atqa; + + memset(handle->uid, 0, sizeof(handle->uid)); + memset(sak, 0, sizeof(sak)); + memset(&atqa, 0, sizeof(atqa)); + memset(&acf, 0, sizeof(acf)); + + ret = iso14443a_transceive_sf(handle, ISO14443A_SF_CMD_REQA, &atqa); + if (ret < 0) { + h->state = ISO14443A_STATE_REQA_SENT; + DEBUGP("error during transceive_sf: %d\n", ret); + return ret; + } + h->state = ISO14443A_STATE_ATQA_RCVD; + + DEBUGP("ATQA: 0x%02x 0x%02x\n", *aqptr, *(aqptr+1)); + + if (!atqa.bf_anticol) { + h->state = ISO14443A_STATE_NO_BITFRAME_ANTICOL; + DEBUGP("no bitframe anticollission bits set, aborting\n"); + return -1; + } + + if (atqa.uid_size == 2 || atqa.uid_size == 3) + uid_size = 3; + else if (atqa.uid_size == 1) + uid_size = 2; + else + uid_size = 1; + + acf.sel_code = ISO14443A_AC_SEL_CODE_CL1; + + h->state = ISO14443A_STATE_ANTICOL_RUNNING; + h->level = ISO14443A_LEVEL_CL1; + +cascade: + iso14443a_code_nvb_bits(&acf.nvb, 16); + + ret = iso14443a_transceive_acf(handle, &acf, &bit_of_col); + if (ret < 0) + return ret; + DEBUGP("bit_of_col = %d\n", bit_of_col); + + while (bit_of_col != ISO14443A_BITOFCOL_NONE) { + set_bit_in_field(&acf.uid_bits[0], bit_of_col-16); + iso14443a_code_nvb_bits(&acf.nvb, bit_of_col); + ret = iso14443a_transceive_acf(handle, &acf, &bit_of_col); + DEBUGP("bit_of_col = %d\n", bit_of_col); + if (ret < 0) + return ret; + } + + iso14443a_code_nvb_bits(&acf.nvb, 7*8); + ret = iso14443a_transceive(handle, RFID_14443A_FRAME_REGULAR, + (unsigned char *)&acf, 7, + (unsigned char *) &sak, &rx_len, + TIMEOUT, 0); + if (ret < 0) + return ret; + + if (sak[0] & 0x04) { + /* Cascade bit set, UID not complete */ + switch (acf.sel_code) { + case ISO14443A_AC_SEL_CODE_CL1: + /* cascading from CL1 to CL2 */ + if (acf.uid_bits[0] != 0x88) { + DEBUGP("Cascade bit set, but UID0 != 0x88\n"); + return -1; + } + memcpy(&handle->uid[0], &acf.uid_bits[1], 3); + acf.sel_code = ISO14443A_AC_SEL_CODE_CL2; + h->level = ISO14443A_LEVEL_CL2; + break; + case ISO14443A_AC_SEL_CODE_CL2: + /* cascading from CL2 to CL3 */ + memcpy(&handle->uid[3], &acf.uid_bits[1], 3); + acf.sel_code = ISO14443A_AC_SEL_CODE_CL3; + h->level = ISO14443A_LEVEL_CL3; + break; + default: + DEBUGP("cannot cascade any further than CL3\n"); + h->state = ISO14443A_STATE_ERROR; + return -1; + break; + } + goto cascade; + + } else { + switch (acf.sel_code) { + case ISO14443A_AC_SEL_CODE_CL1: + /* single size UID (4 bytes) */ + memcpy(&handle->uid[0], &acf.uid_bits[0], 4); + break; + case ISO14443A_AC_SEL_CODE_CL2: + /* double size UID (7 bytes) */ + memcpy(&handle->uid[3], &acf.uid_bits[0], 4); + break; + case ISO14443A_AC_SEL_CODE_CL3: + /* triple size UID (10 bytes) */ + memcpy(&handle->uid[6], &acf.uid_bits[0], 4); + break; + } + } + + h->level = ISO14443A_LEVEL_NONE; + h->state = ISO14443A_STATE_SELECTED; + + { + if (uid_size == 1) + handle->uid_len = 4; + else if (uid_size == 2) + handle->uid_len = 7; + else + handle->uid_len = 10; + + DEBUGP("UID %s\n", rfid_hexdump(handle->uid, handle->uid_len)); + } + + if (sak[0] & 0x20) { + DEBUGP("we have a T=CL compliant PICC\n"); + h->tcl_capable = 1; + } else { + DEBUGP("we have a T!=CL PICC\n"); + h->tcl_capable = 0; + } + + return 0; +} + +static int +iso14443a_hlta(struct rfid_layer2_handle *handle) +{ + int ret; + unsigned char tx_buf[2] = { 0x50, 0x00 }; + unsigned char rx_buf[10]; + unsigned int rx_len = sizeof(rx_buf); + + ret = iso14443a_transceive(handle, RFID_14443A_FRAME_REGULAR, + tx_buf, sizeof(tx_buf), + rx_buf, &rx_len, 1000 /* 1ms */, 0); + if (ret < 0) { + /* "error" case: we don't get somethng back from the card */ + return 0; + } + return -1; +} + +static int +iso14443a_setopt(struct rfid_layer2_handle *handle, int optname, + const void *optval, unsigned int optlen) +{ + int ret = -EINVAL; + unsigned int speed; + + switch (optname) { + case RFID_OPT_14443A_SPEED_RX: + speed = *(unsigned int *)optval; + ret = rc632_iso14443a_set_speed(handle->rh, 0, speed); + break; + case RFID_OPT_14443A_SPEED_TX: + speed = *(unsigned int *)optval; + ret = rc632_iso14443a_set_speed(handle->rh, 1, speed); + break; + }; + + return ret; +} + + +static struct rfid_layer2_handle * +iso14443a_init(struct rfid_reader_handle *rh) +{ + int ret; + struct rfid_layer2_handle *h = malloc(sizeof(*h)); + if (!h) + return NULL; + + h->l2 = &rfid_layer2_iso14443a; + h->rh = rh; + h->priv.iso14443a.state = ISO14443A_STATE_NONE; + h->priv.iso14443a.level = ISO14443A_LEVEL_NONE; + + ret = rc632_iso14443a_init(h->rh); + if (ret < 0) { + free(h); + return NULL; + } + + return h; +} + +static int +iso14443a_fini(struct rfid_layer2_handle *handle) +{ + free(handle); + return 0; +} + +struct rfid_layer2 rfid_layer2_iso14443a = { + .id = RFID_LAYER2_ISO14443A, + .name = "ISO 14443-3 A", + .fn = { + .init = &iso14443a_init, + .open = &iso14443a_anticol, + .transceive = &iso14443a_transceive, + .close = &iso14443a_hlta, + .fini = &iso14443a_fini, + .setopt = &iso14443a_setopt, + }, +}; -- cgit v1.2.3