Add WRITE support for ISO15693 (Bjoern Riemer)
[librfid] / src / rfid_asic_rc632.c
index 57a9888..28bd5a1 100644 (file)
@@ -240,7 +240,7 @@ rc632_timer_set(struct rfid_asic_handle *handle,
                u_int64_t timeout)
 {
        int ret;
-       u_int8_t prescaler, divisor;
+       u_int8_t prescaler, divisor, irq;
 
        timeout *= TIMER_RELAX_FACTOR;
 
@@ -255,7 +255,10 @@ rc632_timer_set(struct rfid_asic_handle *handle,
                              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_clear_irqs(handle, RC632_IRQ_TIMER);
+
+       /* enable timer IRQ */
+       ret |= rc632_reg_write(handle, RC632_REG_INTERRUPT_EN, RC632_IRQ_SET | RC632_IRQ_TIMER);
 
        ret |= rc632_reg_write(handle, RC632_REG_TIMER_RELOAD, divisor);
 
@@ -268,27 +271,44 @@ static int rc632_wait_idle_timer(struct rfid_asic_handle *handle)
        int ret;
        u_int8_t stat, irq, cmd;
 
+       ret = rc632_reg_read(handle, RC632_REG_INTERRUPT_EN, &irq);
+       if (ret < 0)
+               return ret;
+       DEBUGP_INTERRUPT_FLAG("irq_en",irq);
+
+       ret = rc632_reg_write(handle, RC632_REG_INTERRUPT_EN, RC632_IRQ_SET
+                               | RC632_IRQ_TIMER
+                               | RC632_IRQ_IDLE
+                               | RC632_IRQ_RX );
+       if (ret < 0)
+               return ret;
+
        while (1) {
                rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &stat);
                DEBUGP_STATUS_FLAG(stat);
                if (stat & RC632_STAT_ERR) {
                        u_int8_t err;
-                       rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &err);
+                       ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &err);
+                       if (ret < 0)
+                               return ret;
                        DEBUGP_ERROR_FLAG(err);
                        if (err & (RC632_ERR_FLAG_COL_ERR |
                                   RC632_ERR_FLAG_PARITY_ERR |
                                   RC632_ERR_FLAG_FRAMING_ERR |
-                                  RC632_ERR_FLAG_CRC_ERR))
+                               /* FIXME: why get we CRC errors in CL2 anticol at iso14443a operation with mifare UL? */
+                               /*   RC632_ERR_FLAG_CRC_ERR | */
+                                  0))
                                return -EIO;
                }
                if (stat & RC632_STAT_IRQ) {
                        ret = rc632_reg_read(handle, RC632_REG_INTERRUPT_RQ, &irq);
                        if (ret < 0)
                                return ret;
-                       DEBUGP_INTERRUPT_FLAG(irq);
+                       DEBUGP_INTERRUPT_FLAG("irq_rq",irq);
 
                        if (irq & RC632_IRQ_TIMER && !(irq & RC632_IRQ_RX)) {
                                DEBUGP("timer expired before RX!!\n");
+                               rc632_clear_irqs(handle, RC632_IRQ_TIMER);
                                return -ETIMEDOUT;
                        }
                }
@@ -297,8 +317,10 @@ static int rc632_wait_idle_timer(struct rfid_asic_handle *handle)
                if (ret < 0)
                        return ret;
 
-               if (cmd == 0)
+               if (cmd == 0) {
+                       rc632_clear_irqs(handle, RC632_IRQ_RX);
                        return 0;
+               }
 
                /* poll every millisecond */
                usleep(1000);
@@ -333,9 +355,11 @@ rc632_wait_idle(struct rfid_asic_handle *handle, u_int64_t timeout)
                        /* check if IRQ has occurred (IRQ flag set)*/
                        if (foo & RC632_STAT_IRQ) { 
                                ret = rc632_reg_read(handle, RC632_REG_INTERRUPT_RQ, &foo);
-                               DEBUGP_INTERRUPT_FLAG(foo);
+                               DEBUGP_INTERRUPT_FLAG("irq_rq",foo);
                                /* clear all interrupts */
-                               rc632_clear_irqs(handle, 0xff);
+                               ret = rc632_clear_irqs(handle, 0xff);
+                               if (ret < 0)
+                                       return ret;
                        }
                }
                if (cmd == 0) {
@@ -427,18 +451,13 @@ rc632_transceive(struct rfid_asic_handle *handle,
                cur_tx_len = tx_len;
 
 
-       ret = rc632_reg_write(handle, RC632_REG_COMMAND, 0x00);
+       ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_IDLE);
        /* clear all interrupts */
        ret = rc632_reg_write(handle, RC632_REG_INTERRUPT_RQ, 0x7f);
-       ret = rc632_reg_write(handle, RC632_REG_ERROR_FLAG, 0xff);
 
        { u_int8_t tmp;
        rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &tmp);
        DEBUGP_STATUS_FLAG(tmp);
-       rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &tmp);
-       DEBUGP_STATUS_FLAG(tmp);
-       rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &tmp);
-       DEBUGP_STATUS_FLAG(tmp);
        rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &tmp);
        DEBUGP_ERROR_FLAG(tmp);
        }
@@ -506,7 +525,7 @@ rc632_transceive(struct rfid_asic_handle *handle,
                rc632_reg_read(handle, RC632_REG_CHANNEL_REDUNDANCY, &tmp);
 
                //return 0;
-               return -1;
+               return -EIO;
        }
 
        return rc632_fifo_read(handle, *rx_len, rx_buf);
@@ -578,16 +597,69 @@ rc632_receive(struct rfid_asic_handle *handle,
        /* FIXME: discard additional bytes in FIFO */
 }
 
+#define MAX_WRITE_LEN  16      /* see Sec. 18.6.1.2 of RC632 Spec Rev. 3.2. */
+
+static int
+rc632_write_eeprom(struct rfid_asic_handle *handle, u_int16_t addr, 
+                  u_int8_t *data, u_int8_t len)
+{
+       u_int8_t sndbuf[MAX_WRITE_LEN + 2];
+       u_int8_t reg;
+       int ret;
+
+       if (len > MAX_WRITE_LEN)
+               return -EINVAL;
+       if (addr < 0x10)
+               return -EPERM;
+       if (addr > 0x1ff)
+               return -EINVAL;
+
+       sndbuf[0] = addr & 0x00ff;      /* LSB */
+       sndbuf[1] = addr >> 8;          /* MSB */
+       memcpy(&sndbuf[2], data, len);
+
+       ret = rc632_fifo_write(handle, len + 2, sndbuf, 0x03);
+       if (ret < 0)
+               return ret;
+
+       ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_WRITE_E2);
+       if (ret < 0)
+               return ret;
+       
+       ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &reg);
+       if (ret < 0)
+               return ret;
+
+       if (reg & RC632_ERR_FLAG_ACCESS_ERR)
+               return -EPERM;
+
+       while (1) {
+               u_int8_t reg;
+               ret = rc632_reg_read(handle, RC632_REG_SECONDARY_STATUS, &reg);
+               if (ret < 0)
+                       return ret;
+
+               if (reg & RC632_SEC_ST_E2_READY) {
+                       /* the E2Write command must be terminated, See sec. 18.6.1.3 */
+                       ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_IDLE);
+                       break;
+               }
+       }
+       
+       return ret;
+}
+
 static int
-rc632_read_eeprom(struct rfid_asic_handle *handle)
+rc632_read_eeprom(struct rfid_asic_handle *handle, u_int16_t addr,
+                 u_int8_t *buf, u_int8_t len)
 {
-       u_int8_t recvbuf[60];
        u_int8_t sndbuf[3];
+       u_int8_t reg;
        int ret;
 
-       sndbuf[0] = 0x00;
-       sndbuf[1] = 0x00;
-       sndbuf[2] = 0x3c;
+       sndbuf[0] = addr & 0xff;
+       sndbuf[1] = addr >> 8;
+       sndbuf[2] = len;
 
        ret = rc632_fifo_write(handle, 3, sndbuf, 0x03);
        if (ret < 0)
@@ -597,14 +669,16 @@ rc632_read_eeprom(struct rfid_asic_handle *handle)
        if (ret < 0)
                return ret;
 
-       usleep(20000);
-
-       ret = rc632_fifo_read(handle, sizeof(recvbuf), recvbuf);
+       ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &reg);
        if (ret < 0)
                return ret;
 
-       /* FIXME: do something with eeprom contents */
-       return ret;
+       if (reg & RC632_ERR_FLAG_ACCESS_ERR)
+               return -EPERM;
+
+       usleep(20000);
+
+       return rc632_fifo_read(handle, len, buf);
 }
 
 static int
@@ -1523,6 +1597,12 @@ static struct register_file icode1_std_script[] = {
        }, {
                .reg    = RC632_REG_CRC_PRESET_MSB,
                .val    = 0xff,
+       /* }, {
+               .reg    = RC632_REG_INTERRUPT_EN,
+               .val    = RC632_INT_IDLE |
+                         RC632_INT_TIMER |
+                         RC632_INT_RX |
+                         RC632_INT_TX, */
        }
 };
 
@@ -1677,7 +1757,7 @@ rc632_iso15693_transceive_ac(struct rfid_asic_handle *handle,
                             const struct iso15693_anticol_cmd *acf,
                             unsigned int acf_len,
                             struct iso15693_anticol_resp *resp,
-                            unsigned int *rx_len, char *bit_of_col)
+                            unsigned int *rx_len, unsigned char *bit_of_col)
 {
        u_int8_t error_flag, boc;
        //u_int8_t rx_len;
@@ -1693,7 +1773,7 @@ rc632_iso15693_transceive_ac(struct rfid_asic_handle *handle,
        ret = rc632_transceive(handle, (u_int8_t *)acf, acf_len,
                               (u_int8_t *) resp, rx_len, 
                               iso15693_timing[rate][ISO15693_T1], 0);
-       if (ret == -ETIMEDOUT)
+       if (ret == -ETIMEDOUT || ret == -EIO)
                return ret;
 
        /* determine whether there was a collission */
@@ -1702,12 +1782,17 @@ rc632_iso15693_transceive_ac(struct rfid_asic_handle *handle,
                return ret;
        DEBUGP_ERROR_FLAG(error_flag);
 
+       //FIXME: check for framing and crc errors...
        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_col = boc;
+       } else {
+               *bit_of_col = 0;
+               if (error_flag & RC632_ERR_FLAG_CRC_ERR)
+                       return -EIO;
        }
 
        return 0;
@@ -1869,6 +1954,52 @@ rc632_mifare_set_key(struct rfid_asic_handle *h, const u_int8_t *key)
        return 0;
 }
 
+static int
+rc632_mifare_set_key_ee(struct rfid_asic_handle *h, unsigned int addr)
+{
+       int ret;
+       u_int8_t cmd_addr[2];
+       u_int8_t reg;
+
+       if (addr > 0xffff - RFID_MIFARE_KEY_CODED_LEN)
+               return -EINVAL;
+
+       cmd_addr[0] = addr & 0xff;              /* LSB */
+       cmd_addr[1] = (addr >> 8) & 0xff;       /* MSB */
+
+       /* Terminate probably running command */
+       ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_IDLE);    
+       if (ret < 0)
+               return ret;
+
+       /* Write the key address to the FIFO */
+       ret = rc632_fifo_write(h, 2, cmd_addr, 0x03);
+       if (ret < 0)
+               return ret;
+
+       ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_LOAD_KEY_E2);
+       if (ret < 0)
+               return ret;
+
+       ret = rc632_timer_set(h, RC632_TMO_AUTH1);
+       if (ret < 0)
+               return ret;
+
+       //ret = rc632_wait_idle(h, RC632_TMO_AUTH1);
+       ret = rc632_wait_idle_timer(h);
+       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)
@@ -2037,6 +2168,7 @@ const struct rfid_asic rc632 = {
                        },
                        .mifare_classic = {
                                .setkey = &rc632_mifare_set_key,
+                               .setkey_ee = &rc632_mifare_set_key_ee,
                                .auth = &rc632_mifare_auth,
                        },
                },