/* Generic Philips CL RC632 Routines
*
- * (C) Harald Welte <laforge@gnumonks.org>
+ * (C) 2005-2006 Harald Welte <laforge@gnumonks.org>
*
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <limits.h>
#include <sys/types.h>
#include <librfid/rfid.h>
#include "rfid_iso14443_common.h"
#include "rc632.h"
-//#include "rc632_14443a.h"
+#ifdef __MINGW32__
+#include "usleep.h"
+#endif/*__MINGW32__*/
-#define RC632_TMO_AUTH1 14000
+#define RC632_TMO_AUTH1 140
#define ENTER() DEBUGP("entering\n")
-struct rfid_asic rc632;
+const struct rfid_asic rc632;
/* Register and FIFO Access functions */
static int
RC632_CONTROL_POWERDOWN);
}
-/* Stupid RC623 implementations don't evaluate interrupts but poll the
+/* 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_prescaler, best_divisor, i;
+ int64_t smallest_diff;
+
+ smallest_diff = LLONG_MAX;
+ best_prescaler = 0;
+
+ for (i = 0; i < 21; i++) {
+ u_int64_t clk, tmp_div, res;
+ int64_t diff;
+ clk = 13560000 / (1 << i);
+ tmp_div = (clk * timeout) / 1000000;
+ tmp_div++;
+
+ if ((tmp_div > 0xff) || (tmp_div > clk))
+ continue;
+
+ res = 1000000 / (clk / tmp_div);
+ diff = res - timeout;
+
+ if (diff < 0)
+ continue;
+
+ if (diff < smallest_diff) {
+ best_prescaler = i;
+ best_divisor = tmp_div;
+ smallest_diff = diff;
+ }
+ }
+
+ *prescaler = best_prescaler;
+ *divisor = best_divisor;
+
+ DEBUGP("timeout %u usec, prescaler = %u, divisor = %u\n",
+ timeout, best_prescaler, 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, &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_IRQ_TIMER);
+
+ 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) {
+ rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &irq);
+ rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &irq);
+ 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_IRQ_TIMER && !(irq & RC632_IRQ_RX)) {
+ 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);
+
+ return -110;
+ }
+
+ ret = rc632_reg_read(handle, RC632_REG_COMMAND, &cmd);
+ if (ret < 0)
+ return ret;
+
+ if (cmd == 0)
+ return 0;
+
+ /* poll every millisecond */
+ 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)
}
/* Abort after some timeout */
- if (cycles > timeout*10/USLEEP_PER_CYCLE) {
- fprintf(stderr, "TIMEOUT!!\n");
- return -1;
+ if (cycles > timeout*100/USLEEP_PER_CYCLE) {
+ return -ETIMEDOUT;
}
cycles++;
u_int8_t len,
u_int64_t timeout)
{
- int ret;
+ int ret, cur_len;
+ const u_int8_t *cur_buf = buf;
- ret = rc632_fifo_write(handle, len, buf, 0x03);
- if (ret < 0)
- return ret;
+ 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;
- ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_TRANSMIT);
- 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
-rc632_transcieve(struct rfid_asic_handle *handle,
+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,
- unsigned int timer,
+ u_int64_t timer,
unsigned int toggle)
{
- int ret;
+ int ret, cur_tx_len;
+ u_int8_t rx_avail;
+ const u_int8_t *cur_tx_buf = tx_buf;
- ret = rc632_fifo_write(handle, tx_len, tx_buf, 0x03);
- if (ret < 0)
- return ret;
+ DEBUGP("timer = %u\n", timer);
+
+ if (tx_len > 64)
+ cur_tx_len = 64;
+ else
+ cur_tx_len = tx_len;
- ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_TRANSCIEVE);
+ ret = rc632_timer_set(handle, timer*10);
if (ret < 0)
return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_COMMAND, 0x00);
+ /* clear all interrupts */
+ ret = rc632_reg_write(handle, RC632_REG_INTERRUPT_RQ, 0x7f);
+
+ 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;
+ //printf("refilling tx fifo with %u bytes\n", 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);
ret = rc632_wait_idle(handle, timer);
if (ret < 0)
return ret;
- ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, rx_len);
+ ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, &rx_avail);
if (ret < 0)
return ret;
- if (*rx_len == 0) {
+ if (rx_avail > *rx_len) {
+ //printf("rx_avail(%d) > rx_len(%d), JFYI\n", rx_avail, *rx_len);
+ } else if (*rx_len > rx_avail)
+ *rx_len = rx_avail;
+
+ if (rx_avail == 0) {
u_int8_t tmp;
DEBUGP("rx_len == 0\n");
}
return rc632_fifo_read(handle, *rx_len, rx_buf);
+ /* FIXME: discard addidional bytes in FIFO */
}
static int
if (ret < 0)
return ret;
+ /* switch off rf */
+ ret = rc632_turn_off_rf(ah);
+ if (ret < 0)
+ return ret;
+
+ usleep(100000);
+
/* switch on rf */
ret = rc632_turn_on_rf(ah);
if (ret < 0)
{
struct rfid_asic_handle *h;
- h = malloc(sizeof(*h));
+ h = malloc_asic_handle(sizeof(*h));
if (!h)
return NULL;
memset(h, 0, sizeof(*h));
- h->asic = &rc632;
+ h->asic = (void*)&rc632;
h->rath = th;
h->fc = h->asic->fc;
- h->mtu = h->mru = 40; /* FIXME */
+ /* FIXME: this is only cm5121 specific, since the latency
+ * down to the RC632 FIFO is too long to refill during TX/RX */
+ h->mtu = h->mru = 64;
if (rc632_init(h) < 0) {
- free(h);
+ free_asic_handle(h);
return NULL;
}
rc632_close(struct rfid_asic_handle *h)
{
rc632_fini(h);
- free(h);
+ free_asic_handle(h);
}
/*
* Philips CL RC632 primitives for ISO 14443-A compliant PICC's
*
- * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2005-2006 by Harald Welte <laforge@gnumonks.org>
*
*/
// 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_CONTROL,
+ RC632_CONTROL_FIFO_FLUSH);
ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL,
(RC632_TXCTRL_TX1_RF_EN |
/* issue a 14443-3 A PCD -> PICC command in a short frame, such as REQA, WUPA */
static int
-rc632_iso14443a_transcieve_sf(struct rfid_asic_handle *handle,
+rc632_iso14443a_transceive_sf(struct rfid_asic_handle *handle,
u_int8_t cmd,
struct iso14443a_atqa *atqa)
{
u_int8_t tx_buf[1];
u_int8_t rx_len = 2;
- memset(atqa, 0, sizeof(atqa));
+ memset(atqa, 0, sizeof(*atqa));
tx_buf[0] = cmd;
if (ret < 0)
return ret;
- ret = rc632_transcieve(handle, tx_buf, sizeof(tx_buf),
- (u_int8_t *)atqa, &rx_len, 0x32, 0);
+ ret = rc632_transceive(handle, tx_buf, sizeof(tx_buf),
+ (u_int8_t *)atqa, &rx_len,
+ ISO14443A_FDT_ANTICOL_LAST1, 0);
if (ret < 0) {
- DEBUGP("error during rc632_transcieve()\n");
+ DEBUGP("error during rc632_transceive()\n");
return ret;
}
return 0;
}
-/* transcieve regular frame */
+/* transceive regular frame */
static int
-rc632_iso14443ab_transcieve(struct rfid_asic_handle *handle,
+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 rxl;
u_int8_t channel_red;
+ if (*rx_len > 0xff)
+ rxl = 0xff;
+ else
+ rxl = *rx_len;
+
memset(rx_buf, 0, *rx_len);
switch (frametype) {
if (ret < 0)
return ret;
- ret = rc632_transcieve(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0);
+ ret = rc632_transceive(handle, tx_buf, tx_len, rx_buf, &rxl, timeout, 0);
*rx_len = rxl;
if (ret < 0)
return ret;
return 0;
}
-/* transcieve anti collission bitframe */
+/* transceive anti collission bitframe */
static int
-rc632_iso14443a_transcieve_acf(struct rfid_asic_handle *handle,
+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 rx_align = 0, tx_last_bits, tx_bytes, tx_bytes_total;
u_int8_t boc;
u_int8_t error_flag;
*bit_of_col = ISO14443A_BITOFCOL_NONE;
if (ret < 0)
return ret;
- tx_last_bits = acf->nvb & 0x0f; /* lower nibble indicates bits */
- tx_bytes = acf->nvb >> 4;
+ tx_last_bits = acf->nvb & 0x07; /* lower nibble indicates bits */
+ tx_bytes = ( acf->nvb >> 4 ) & 0x07;
if (tx_last_bits) {
- tx_bytes++;
- rx_align = (tx_last_bits+1) % 8;/* rx frame complements tx */
+ tx_bytes_total = tx_bytes+1;
+ rx_align = tx_last_bits & 0x07; /* rx frame complements tx */
}
-
- //rx_align = 8 - tx_last_bits;/* rx frame complements tx */
+ else
+ tx_bytes_total = tx_bytes;
/* set RxAlign and TxLastBits*/
ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING,
if (ret < 0)
return ret;
- ret = rc632_transcieve(handle, (u_int8_t *)acf, tx_bytes,
+ ret = rc632_transceive(handle, (u_int8_t *)acf, tx_bytes_total,
rx_buf, &rx_len, 0x32, 0);
if (ret < 0)
return ret;
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);
+ if(rx_len)
+ memcpy(&acf->uid_bits[tx_bytes-1], &rx_buf[1], rx_len-1);
/* determine whether there was a collission */
ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &error_flag);
};
static int rc632_iso14443a_set_speed(struct rfid_asic_handle *handle,
- unsigned int tx,
- u_int8_t rate)
+ unsigned int tx, unsigned int rate)
{
int rc;
u_int8_t reg;
// FIXME: some FIFO work
/* flush fifo (our way) */
- ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01);
+ ret = rc632_reg_write(handle, RC632_REG_CONTROL,
+ RC632_CONTROL_FIFO_FLUSH);
if (ret < 0)
return ret;
if (ret < 0)
return ret;
+ /* Terminate probably running command */
+ ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_IDLE);
+ if (ret < 0)
+ return ret;
+
ret = rc632_fifo_write(h, RFID_MIFARE_KEY_CODED_LEN, coded_key, 0x03);
if (ret < 0)
return ret;
struct mifare_authcmd acmd;
u_int8_t reg;
- if (cmd != RFID_CMD_MIFARE_AUTH1A && cmd != RFID_CMD_MIFARE_AUTH1B)
+ if (cmd != RFID_CMD_MIFARE_AUTH1A && cmd != RFID_CMD_MIFARE_AUTH1B) {
+ DEBUGP("invalid auth command\n");
return -EINVAL;
+ }
/* Initialize acmd */
acmd.block_address = block & 0xff;
//acmd.serno = htonl(serno);
acmd.serno = serno;
+#if 1
/* Clear Rx CRC */
ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY,
RC632_CR_RX_CRC_ENABLE);
+#else
+ /* Clear Rx CRC, Set Tx CRC and Odd Parity */
+ ret = rc632_reg_write(h, RC632_REG_CHANNEL_REDUNDANCY,
+ RC632_CR_TX_CRC_ENABLE | RC632_CR_PARITY_ODD |
+ RC632_CR_PARITY_ENABLE);
+#endif
if (ret < 0)
return ret;
return ret;
ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT1);
- if (ret < 0)
+ if (ret < 0) {
+ DEBUGP("error during AUTHENT1");
return ret;
+ }
/* Wait until transmitter is idle */
ret = rc632_wait_idle(h, RC632_TMO_AUTH1);
ret = rc632_reg_read(h, RC632_REG_SECONDARY_STATUS, ®);
if (ret < 0)
return ret;
- if (reg & 0x07)
+ if (reg & 0x07) {
+ DEBUGP("bitframe?");
return -EIO;
+ }
/* Clear Tx CRC */
ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY,
if (ret < 0)
return ret;
- if (!(reg & RC632_CONTROL_CRYPTO1_ON))
+ if (!(reg & RC632_CONTROL_CRYPTO1_ON)) {
+ DEBUGP("authentication not successful");
return -EACCES;
+ }
return 0;
-
}
-/* transcieve regular frame */
+/* transceive regular frame */
static int
-rc632_mifare_transcieve(struct rfid_asic_handle *handle,
+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)
if (ret < 0)
return ret;
- ret = rc632_transcieve(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0);
+ ret = rc632_transceive(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0);
*rx_len = rxl;
if (ret < 0)
return ret;
return 0;
}
-struct rfid_asic rc632 = {
+const struct rfid_asic rc632 = {
.name = "Philips CL RC632",
.fc = ISO14443_FREQ_CARRIER,
.priv.rc632 = {
.power_down = &rc632_power_down,
.turn_on_rf = &rc632_turn_on_rf,
.turn_off_rf = &rc632_turn_off_rf,
- .transcieve = &rc632_iso14443ab_transcieve,
+ .transceive = &rc632_iso14443ab_transceive,
.iso14443a = {
.init = &rc632_iso14443a_init,
- .transcieve_sf = &rc632_iso14443a_transcieve_sf,
- .transcieve_acf = &rc632_iso14443a_transcieve_acf,
+ .transceive_sf = &rc632_iso14443a_transceive_sf,
+ .transceive_acf = &rc632_iso14443a_transceive_acf,
.set_speed = &rc632_iso14443a_set_speed,
},
.iso14443b = {