summaryrefslogtreecommitdiff
path: root/firmware/src/pcd
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/src/pcd')
-rw-r--r--firmware/src/pcd/main_analog.c85
-rw-r--r--firmware/src/pcd/main_dumbreader.c63
-rw-r--r--firmware/src/pcd/main_pwm.c257
-rw-r--r--firmware/src/pcd/main_reqa.c265
-rw-r--r--firmware/src/pcd/rc632.c624
-rw-r--r--firmware/src/pcd/rc632.h31
-rw-r--r--firmware/src/pcd/rc632_highlevel.c1473
-rw-r--r--firmware/src/pcd/rfid_layer2_iso14443a.c319
8 files changed, 3117 insertions, 0 deletions
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 <errno.h>
+#include <string.h>
+#include <librfid/rfid_layer2_iso14443a.h>
+#include "rc632.h"
+#include <os/dbgu.h>
+#include <os/led.h>
+#include <os/trigger.h>
+#include <os/pcd_enumerate.h>
+#include <os/main.h>
+
+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 <errno.h>
+#include <include/lib_AT91SAM7.h>
+#include <include/openpcd.h>
+#include <os/dbgu.h>
+#include "rc632.h"
+#include <os/led.h>
+#include <os/pcd_enumerate.h>
+#include <os/usb_handler.h>
+#include "../openpcd.h"
+#include <os/main.h>
+
+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 <errno.h>
+#include <string.h>
+#include <lib_AT91SAM7.h>
+#include "../openpcd.h"
+#include <pcd/rc632.h>
+#include <os/dbgu.h>
+#include <os/led.h>
+#include <os/pwm.h>
+#include <os/tc_cdiv.h>
+#include <os/pcd_enumerate.h>
+#include <os/usb_handler.h>
+
+#ifdef SSC
+#include <pcd/ssc.h>
+#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 <errno.h>
+#include <string.h>
+#include <lib_AT91SAM7.h>
+#include <librfid/rfid_layer2_iso14443a.h>
+#include "rc632.h"
+#include <os/dbgu.h>
+#include <os/led.h>
+#include <os/pcd_enumerate.h>
+#include <os/trigger.h>
+
+#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 <hwelte@hmw-consulting.de>
+ *
+ * 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 <string.h>
+#include <errno.h>
+#include <lib_AT91SAM7.h>
+#include <cl_rc632.h>
+#include <openpcd.h>
+#include "../openpcd.h"
+#include <os/fifo.h>
+#include <os/dbgu.h>
+#include <os/pcd_enumerate.h>
+#include <os/usb_handler.h>
+#include <os/req_ctx.h>
+#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 <sys/types.h>
+#include <cl_rc632.h>
+#include <librfid/rfid.h>
+
+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 <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ * 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 <sys/types.h>
+#include <string.h>
+#include <errno.h>
+#include <cl_rc632.h>
+#include "rc632.h"
+#include <os/dbgu.h>
+#include <librfid/rfid_layer2_iso14443a.h>
+#include <librfid/rfid_protocol_mifare_classic.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
+
+#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 <laforge@gnumonks.org>
+ *
+ */
+
+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)<<RC632_BPSKD_TAUB_SHIFT |
+ (0x3 & RC632_BPSKD_TAUD_MASK)<<RC632_BPSKD_TAUD_SHIFT |
+ RC632_BPSKD_FILTER_AMP_DETECT |
+ RC632_BPSKD_NO_RX_EOF |
+ RC632_BPSKD_NO_RX_EGT));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2,
+ (RC632_RXCTRL2_AUTO_PD |
+ RC632_RXCTRL2_DECSRC_INT));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_RX_WAIT, 0x03);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+ (RC632_CR_TX_CRC_ENABLE |
+ RC632_CR_RX_CRC_ENABLE |
+ RC632_CR_CRC3309));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0xff);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+rc632_iso15693_init(struct rfid_asic_handle *h)
+{
+ int ret;
+
+ ret = rc632_reg_write(h, RC632_REG_TX_CONTROL,
+ (RC632_TXCTRL_MOD_SRC_INT |
+ RC632_TXCTRL_TX2_INV |
+ RC632_TXCTRL_TX2_RF_EN |
+ RC632_TXCTRL_TX1_RF_EN));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CW_CONDUCTANCE, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_CONDUCTANCE, 0x03);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CODER_CONTROL,
+ (RC632_CDRCTRL_RATE_15693 |
+ 0x03)); /* FIXME */
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_TYPE_B_FRAMING, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL1,
+ (RC632_RXCTRL1_SUBCP_16 |
+ RC632_RXCTRL1_ISO15693 |
+ RC632_RXCTRL1_GAIN_35DB));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_DECODER_CONTROL,
+ (RC632_DECCTRL_RXFR_15693 |
+ RC632_DECCTRL_RX_INVERT));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BIT_PHASE, 0xe0);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_THRESHOLD, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL2,
+ (RC632_RXCTRL2_AUTO_PD |
+ RC632_RXCTRL2_DECSRC_INT));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CHANNEL_REDUNDANCY,
+ (RC632_CR_CRC3309 |
+ RC632_CR_RX_CRC_ENABLE |
+ RC632_CR_TX_CRC_ENABLE));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_LSB, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_MSB, 0xff);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+rc632_iso15693_icode_init(struct rfid_asic_handle *h)
+{
+ int ret;
+
+ ret = rc632_reg_write(h, RC632_REG_TX_CONTROL,
+ (RC632_TXCTRL_MOD_SRC_INT |
+ RC632_TXCTRL_TX2_INV |
+ RC632_TXCTRL_TX2_RF_EN |
+ RC632_TXCTRL_TX1_RF_EN));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CW_CONDUCTANCE, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_CONDUCTANCE, 0x02);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CODER_CONTROL, 0x2c);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_TYPE_B_FRAMING, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL1, 0x8b); /* FIXME */
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_DECODER_CONTROL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BIT_PHASE, 0x52);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_THRESHOLD, 0x66);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL2,
+ RC632_RXCTRL2_DECSRC_INT);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CHANNEL_REDUNDANCY,
+ (RC632_CR_RX_CRC_ENABLE |
+ RC632_CR_TX_CRC_ENABLE));
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_LSB, 0xfe);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_MSB, 0xff);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+rc632_iso15693_icl_init(struct rfid_asic_handle *h)
+{
+ int ret;
+
+ /* ICL */
+
+ ret = rc632_reg_write(h, RC632_REG_TX_CONTROL,
+ (RC632_TXCTRL_MOD_SRC_INT |
+ RC632_TXCTRL_TX2_INV |
+ RC632_TXCTRL_TX2_RF_EN |
+ RC632_TXCTRL_TX1_RF_EN));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CW_CONDUCTANCE, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_CONDUCTANCE, 0x11);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CODER_CONTROL,
+ (RC632_CDRCTRL_RATE_15693 |
+ RC632_CDRCTRL_TXCD_ICODE_STD |
+ 0x03)); /* FIXME */
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+ if (ret < 0)
+ return ret;
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL1,
+ (RC632_RXCTRL1_SUBCP_16|
+ RC632_RXCTRL1_ISO15693|
+ RC632_RXCTRL1_GAIN_35DB));
+ if (ret < 0)
+ return ret;
+ ret = rc632_reg_write(h, RC632_REG_DECODER_CONTROL,
+ (RC632_DECCTRL_RX_INVERT|
+ RC632_DECCTRL_RXFR_15693));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BIT_PHASE, 0xbd);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_THRESHOLD, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL2,
+ RC632_RXCTRL2_DECSRC_INT);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CHANNEL_REDUNDANCY, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_LSB, 0x12);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_MSB, 0xe0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+struct mifare_authcmd {
+ u_int8_t auth_cmd;
+ u_int8_t block_address;
+ u_int32_t serno; /* lsb 1 2 msb */
+} __attribute__ ((packed));
+
+
+#define RFID_MIFARE_KEY_LEN 6
+#define RFID_MIFARE_KEY_CODED_LEN 12
+
+/* Transform crypto1 key from generic 6byte into rc632 specific 12byte */
+static int
+rc632_mifare_transform_key(const u_int8_t *key6, u_int8_t *key12)
+{
+ int i;
+ u_int8_t ln;
+ u_int8_t hn;
+
+ for (i = 0; i < RFID_MIFARE_KEY_LEN; i++) {
+ ln = key6[i] & 0x0f;
+ hn = key6[i] >> 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, &reg);
+ 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, &reg);
+ 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, &reg);
+ 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 <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_layer2.h>
+//#include <librfid/rfid_reader.h>
+#include <librfid/rfid_layer2_iso14443a.h>
+
+#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,
+ },
+};
personal git repositories of Harald Welte. Your mileage may vary