nfctype3: Detect blank tags while reading
authorRavi kumar Veeramally <ravikumar.veeramally@linux.intel.com>
Mon, 20 Aug 2012 15:16:26 +0000 (18:16 +0300)
committerSamuel Ortiz <sameo@linux.intel.com>
Thu, 23 Aug 2012 13:07:28 +0000 (15:07 +0200)
If tag is empty means no NDEF content in tag does not support
system code 0x12FC(in polling). In case of blank tags polling
request response is an error. Finding out tag is blank or not
couple of more steps added before tag reading. Currently it
supports only Felica Lite.
   1) Poll Type-3 tag with 0xFFFF system code.
   2) In response to poll command, tag ID and manufacturer parameter
      will be received. And Manufacturer information contains IC Type
      which is used to identify the tag is Felica Lite, LiteS or other.
   3) Depends upon the tag, read block number 0x88(MC Block) which
      contains memory configuration.
   4) MC contains system code(byte3) related information. If tag is
      blank then it is '0x00', if tag supports NDEF( that means it
      supports system code 0x12FC) then it is '0x01'.
   5) If byte3 is 0x00 then it as 'Blank tag', if it contains 0x01
      then detect ndef(poll with 12FC), read and write.
   6) In case tag is not Felica Lite series then detect ndef
      (poll with 12FC), read and write.

plugins/nfctype3.c

index 7dbd577..8eff338 100644 (file)
 
 #define MAX_DATA_SIZE  254
 
+#define IC_TYPE_OFFSET 12
+#define SYSTEM_OPTION_OFFSET   17
+#define FELICA_LITE_MC_BLOCK   0x88
+#define FELICA_LITE_IC_TYPE    0xF0
+#define FELICA_LITE_S_IC_TYPE  0xF1
+#define FELICA_PLUG_IC_TYPE    0xE0
+
 struct type3_cmd {
        uint8_t len;
        uint8_t cmd;
@@ -115,6 +122,7 @@ struct t3_cookie {
        uint8_t current_block;
        uint8_t attr[BLOCK_SIZE];
        struct near_ndef_message *ndef;
+       uint8_t ic_type;
 };
 
 static void t3_cookie_release(struct t3_cookie *cookie)
@@ -331,6 +339,8 @@ static int nfctype3_recv_block_0(uint8_t *resp, int length, void *data)
 
        near_tag_set_idm(tag, cookie->IDm, LEN_ID);
        near_tag_set_attr_block(tag, resp + OFS_READ_DATA, BLOCK_SIZE);
+       near_tag_set_blank(tag, FALSE);
+       near_tag_set_ic_type(tag, cookie->ic_type);
 
        t3_tag->adapter_idx = cookie->adapter_idx;
        t3_tag->cb = cookie->cb;
@@ -352,10 +362,9 @@ out:
        return err;
 }
 
-static int nfctype3_recv_UID(uint8_t *resp, int length, void *data)
+static int poll_ndef_system_code(uint8_t *resp, int length, void *data)
 {
-       struct t3_cookie *rcv_cookie = data;
-       struct t3_cookie *snd_cookie = NULL;
+       struct t3_cookie *cookie = data;
        int err = 0;
        struct type3_cmd cmd;
 
@@ -370,33 +379,154 @@ static int nfctype3_recv_UID(uint8_t *resp, int length, void *data)
        if (err < 0)
                goto out;
 
-       snd_cookie = g_try_malloc0(sizeof(struct t3_cookie));
-       if (snd_cookie == NULL) {
-               err = -ENOMEM;
+       prepare_read_block(META_BLOCK_START, cookie->IDm, &cmd);
+
+       err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+                               cmd.len, nfctype3_recv_block_0, cookie);
+       if (err < 0)
+               goto out;
+
+       return 0;
+
+out:
+       if (err < 0 && cookie->cb)
+               cookie->cb(cookie->adapter_idx,
+                               cookie->target_idx, err);
+
+       t3_cookie_release(cookie);
+
+       return err;
+}
+
+static int check_sys_op_in_mc_block(uint8_t *resp, int length, void *data)
+{
+       struct type3_cmd cmd;
+       struct near_tag *tag;
+       struct t3_cookie *cookie = data;
+       int err = 0;
+
+       DBG("length %d", length);
+
+       if (length < 0) {
+               err = -EIO;
                goto out;
        }
 
-       snd_cookie->adapter_idx = rcv_cookie->adapter_idx;
-       snd_cookie->target_idx = rcv_cookie->target_idx;
-       snd_cookie->cb = rcv_cookie->cb;
+       err = check_recv_frame(resp, RESP_READ_WO_ENCRYPT);
+       if (err < 0)
+               goto out;
+
+       if (resp[SYSTEM_OPTION_OFFSET] == 0x00) {
+               DBG("Blank tag detected");
 
-       memcpy(snd_cookie->IDm, resp + OFS_IDM, LEN_ID);
+               err = near_tag_add_data(cookie->adapter_idx,
+                                       cookie->target_idx,
+                                       NULL, 1 /* dummy length */);
+               if (err < 0)
+                       goto out;
+
+               tag = near_tag_get_tag(cookie->adapter_idx,
+                                       cookie->target_idx);
+               if (tag == NULL) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               near_tag_set_idm(tag, cookie->IDm, LEN_ID);
+               near_tag_set_ic_type(tag, cookie->ic_type);
+               near_tag_set_blank(tag, TRUE);
+
+               if (cookie->cb)
+                       cookie->cb(cookie->adapter_idx,
+                                       cookie->target_idx, 0);
+
+               t3_cookie_release(cookie);
+
+               return 0;
+       } else {
+               /* CMD POLL */
+               cmd.cmd  = CMD_POLL;    /* POLL command */
+               cmd.data[0] = 0x12;     /* System code (NFC SC) */
+               cmd.data[1] = 0xFC;
+               cmd.data[2] = 01;       /* request code */
+               cmd.data[3] = 0x00;     /* time slot */
+               /* data len + 2 bytes */
+               cmd.len = LEN_CMD + LEN_CMD_LEN + 4 ;
+
+               err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+                       cmd.len , poll_ndef_system_code, cookie);
+       }
 
-       prepare_read_block(META_BLOCK_START, snd_cookie->IDm, &cmd);
+       if (err < 0)
+               goto out;
 
-       err = near_adapter_send(snd_cookie->adapter_idx,
-                       (uint8_t *)&cmd, cmd.len, nfctype3_recv_block_0, snd_cookie);
+       return 0;
 
 out:
-       if (err < 0) {
-               if (rcv_cookie->cb)
-                       rcv_cookie->cb(rcv_cookie->adapter_idx,
-                                       rcv_cookie->target_idx, err);
+       if (err < 0 && cookie->cb)
+               cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
+
+       t3_cookie_release(cookie);
+
+       return err;
+}
+
+static int receive_system_code(uint8_t *resp, int length, void *data)
+{
+       struct t3_cookie *cookie = data;
+       int err = 0;
+       struct type3_cmd cmd;
+       uint16_t system_code;
+
+       DBG(" length: %d", length);
+
+       if (length < 0) {
+               err = -EIO;
+               goto out;
+       }
 
-               g_free(snd_cookie);
+       err = check_recv_frame(resp, RESP_POLL);
+       if (err < 0)
+               goto out;
+
+       cookie->ic_type = resp[IC_TYPE_OFFSET];
+       memcpy(cookie->IDm, resp + OFS_IDM, LEN_ID);
+       system_code = ((uint16_t)(resp[length - 2])) << 8;
+       system_code |= resp[length - 1];
+
+       switch (resp[IC_TYPE_OFFSET]) {
+       case FELICA_LITE_IC_TYPE:
+               prepare_read_block(FELICA_LITE_MC_BLOCK, cookie->IDm, &cmd);
+               err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+                                       cmd.len, check_sys_op_in_mc_block,
+                                       cookie);
+               break;
+
+       case FELICA_LITE_S_IC_TYPE:
+       case FELICA_PLUG_IC_TYPE:
+               /* CMD POLL */
+               cmd.cmd  = CMD_POLL;    /* POLL command */
+               cmd.data[0] = 0x12;     /* System code (NFC SC) */
+               cmd.data[1] = 0xFC;
+               cmd.data[2] = 01;       /* request code */
+               cmd.data[3] = 0x00;     /* time slot */
+               /* data len + 2 bytes */
+               cmd.len = LEN_CMD + LEN_CMD_LEN + 4 ;
+
+               err = near_adapter_send(cookie->adapter_idx, (uint8_t *)&cmd,
+                                       cmd.len, poll_ndef_system_code, cookie);
        }
 
-       t3_cookie_release(rcv_cookie);
+       if (err < 0)
+               goto out;
+
+       return 0;
+
+out:
+       if (err < 0 && cookie->cb)
+               cookie->cb(cookie->adapter_idx, cookie->target_idx, err);
+
+       t3_cookie_release(cookie);
 
        return err;
 }
@@ -412,8 +542,8 @@ static int nfctype3_read(uint32_t adapter_idx,
 
        /* CMD POLL */
        cmd.cmd  = CMD_POLL;    /* POLL command */
-       cmd.data[0] = 0x12;     /* System code (NFC SC) */
-       cmd.data[1] = 0xFC;
+       cmd.data[0] = 0xFF;     /* System code */
+       cmd.data[1] = 0xFF;
        cmd.data[2] = 01;       /* request code */
        cmd.data[3] = 0x00;     /* time slot */
 
@@ -429,7 +559,7 @@ static int nfctype3_read(uint32_t adapter_idx,
        cookie->cb = cb;
 
        err = near_adapter_send(adapter_idx, (uint8_t *)&cmd,
-                               cmd.len , nfctype3_recv_UID, cookie);
+                               cmd.len , receive_system_code, cookie);
        if (err < 0)
                g_free(cookie);