add function to set mifare key from internal eeprom
[librfid] / src / rfid_asic_rc632.c
index 4286565..effe813 100644 (file)
@@ -1,6 +1,6 @@
 /* Generic Philips CL RC632 Routines
  *
- * (C) 2005-2006 Harald Welte <laforge@gnumonks.org>
+ * (C) 2005-2008 Harald Welte <laforge@gnumonks.org>
  *
  */
 
@@ -19,8 +19,6 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define DEBUG_LIBRFID
-
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
@@ -556,7 +554,7 @@ rc632_receive(struct rfid_asic_handle *handle,
                return ret;
 
        if (rx_avail > *rx_len) {
-               //printf("rx_avail(%d) > rx_len(%d), JFYI\n", rx_avail, *rx_len);
+               //DEBUGP("rx_avail(%d) > rx_len(%d), JFYI\n", rx_avail, *rx_len);
        } else if (*rx_len > rx_avail)
                *rx_len = rx_avail;
 
@@ -580,16 +578,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)
@@ -599,14 +650,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
@@ -1690,7 +1743,7 @@ rc632_iso15693_transceive_ac(struct rfid_asic_handle *handle,
        if (acf->req.flags & RFID_15693_F_RATE_HIGH)
                rate = ISO15693_T_FAST;
 
-       printf("acf = %s\n", rfid_hexdump(acf, acf_len));
+       DEBUGP("acf = %s\n", rfid_hexdump(acf, acf_len));
 
        ret = rc632_transceive(handle, (u_int8_t *)acf, acf_len,
                               (u_int8_t *) resp, rx_len, 
@@ -1871,6 +1924,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)
@@ -2039,6 +2138,7 @@ const struct rfid_asic rc632 = {
                        },
                        .mifare_classic = {
                                .setkey = &rc632_mifare_set_key,
+                               .setkey_ee = &rc632_mifare_set_key_ee,
                                .auth = &rc632_mifare_auth,
                        },
                },