Improve support for Type 5 high density Tagi (>8K).

Add extended commands as defined by NFC Forum for Type 5.
This set of commands allows to address range of blocks above 8K.
NDEF Native support for high density STM25DV tags is improved.
Large NDEFs (VCARD with a photo) are now supported.

Test: Done on Nexus 6P. Large NDEFs written on ST25DV (64K And 16K).
Check that these NDEFs are natively supported.

Change-Id: I0092920fce5ab29f4d0a75317a9a94a971a17bbb
Signed-off-by: Raphael Collado <raphael.collado@st.com>
diff --git a/src/nfc/include/rw_api.h b/src/nfc/include/rw_api.h
index e634aca..cd6d086 100644
--- a/src/nfc/include/rw_api.h
+++ b/src/nfc/include/rw_api.h
@@ -1071,7 +1071,7 @@
 **                  NFC_STATUS_FAILED if other error
 **
 *******************************************************************************/
-extern tNFC_STATUS RW_I93WriteMultipleBlocks(uint8_t first_block_number,
+extern tNFC_STATUS RW_I93WriteMultipleBlocks(uint16_t first_block_number,
                                              uint16_t number_blocks,
                                              uint8_t* p_data);
 
diff --git a/src/nfc/include/rw_int.h b/src/nfc/include/rw_int.h
index e6d1c71..146df57 100644
--- a/src/nfc/include/rw_int.h
+++ b/src/nfc/include/rw_int.h
@@ -619,6 +619,8 @@
 #define RW_I93_FLAG_RESET_AFI 0x08
 /* use 2 bytes for number of blocks        */
 #define RW_I93_FLAG_16BIT_NUM_BLOCK 0x10
+/* use extended commands */
+#define RW_I93_FLAG_EXT_COMMANDS 0x20
 
 /* searching for type                      */
 #define RW_I93_TLV_DETECT_STATE_TYPE 0x01
@@ -647,6 +649,8 @@
   RW_I93_STM_M24LR04E_R,             /* STM M24LR04E-R                   */
   RW_I93_STM_M24LR16E_R,             /* STM M24LR16E-R                   */
   RW_I93_STM_M24LR64E_R,             /* STM M24LR64E-R                   */
+  RW_I93_STM_ST25DV04K,              /* STM ST25DV04K                    */
+  RW_I93_STM_ST25DVHIK,              /* STM ST25DV 16K OR 64K            */
   RW_I93_UNKNOWN_PRODUCT             /* Unknwon product version          */
 };
 
diff --git a/src/nfc/include/tags_defs.h b/src/nfc/include/tags_defs.h
index 3494827..dc54d78 100644
--- a/src/nfc/include/tags_defs.h
+++ b/src/nfc/include/tags_defs.h
@@ -503,10 +503,15 @@
 
 /* ISO 15693 Optional commands */
 #define I93_CMD_READ_SINGLE_BLOCK 0x20  /* Read single block     */
+#define I93_CMD_EXT_READ_SINGLE_BLOCK 0x30 /* Extended Read single block */
 #define I93_CMD_WRITE_SINGLE_BLOCK 0x21 /* Write single block    */
+#define I93_CMD_EXT_WRITE_SINGLE_BLOCK 0x31 /* Extended Write single block */
 #define I93_CMD_LOCK_BLOCK 0x22         /* Lock block            */
+#define I93_CMD_EXT_LOCK_BLOCK 0x32     /* Extended Lock block            */
 #define I93_CMD_READ_MULTI_BLOCK 0x23   /* Read multiple blocks  */
+#define I93_CMD_EXT_READ_MULTI_BLOCK 0x33 /* Extended Read multiple blocks  */
 #define I93_CMD_WRITE_MULTI_BLOCK 0x24  /* Write multiple blocks */
+#define I93_CMD_EXT_WRITE_MULTI_BLOCK 0x34 /* Write multiple blocks */
 #define I93_CMD_SELECT 0x25             /* Select                */
 #define I93_CMD_RESET_TO_READY 0x26     /* Reset to ready        */
 #define I93_CMD_WRITE_AFI 0x27          /* Wreite AFI            */
@@ -515,8 +520,12 @@
 #define I93_CMD_LOCK_DSFID 0x2A         /* Lock DSFID            */
 /* Get system information             */
 #define I93_CMD_GET_SYS_INFO 0x2B
+/* Get extended system information    */
+#define I93_CMD_EXT_GET_SYS_INFO 0x3B
 /* Get multiple block security status */
 #define I93_CMD_GET_MULTI_BLK_SEC 0x2C
+/* Get extended multiple block security status */
+#define I93_CMD_EXT_GET_MULTI_BLK_SEC 0x3C
 
 /* Information flags definition */
 /* DSFID is supported and DSFID field is present */
@@ -527,12 +536,15 @@
 #define I93_INFO_FLAG_MEM_SIZE 0x04
 /* IC reference field is present                 */
 #define I93_INFO_FLAG_IC_REF 0x08
+/* Memory coded in 2 bytes address               */
+#define I93_INFO_FLAG_MOI 0x10
 
 /* Max block size in bytes */
 #define I93_MAX_BLOCK_LENGH 32
 
 /* ICODE Capability Container(CC) definition */
-#define I93_ICODE_CC_MAGIC_NUMER 0xE1    /* magic number in CC[0]  */
+#define I93_ICODE_CC_MAGIC_NUMER_E1 0xE1 /* magic number in CC[0]  */
+#define I93_ICODE_CC_MAGIC_NUMER_E2 0xE2 /* magic number in CC[0]  */
 /* read access condition in CC[1]        */
 #define I93_ICODE_CC_READ_ACCESS_MASK 0x0C
 /* read access granted without security  */
@@ -620,6 +632,13 @@
 /* IC Reference for M24LR64E-R: 01011110(b), blockSize: 4, numberBlocks: 0x800
  */
 #define I93_IC_REF_STM_M24LR64E_R 0x5E
+/* IC Reference for ST25DV04K: 00100100(b), blockSize: 4, numberBlocks: 0x80
+ */
+#define I93_IC_REF_STM_ST25DV04K 0x24
+/* IC Reference for ST25DVHIK: 00100110(b), blockSize: 4, numberBlocks: 0x800
+ * or 0x200
+ */
+#define I93_IC_REF_STM_ST25DVHIK 0x26
 
 #define I93_STM_BLOCKS_PER_SECTOR 32
 #define I93_STM_MAX_BLOCKS_PER_READ 32
diff --git a/src/nfc/tags/rw_i93.cc b/src/nfc/tags/rw_i93.cc
index 75dacab..2f1b3cd 100644
--- a/src/nfc/tags/rw_i93.cc
+++ b/src/nfc/tags/rw_i93.cc
@@ -88,6 +88,7 @@
                               tNFC_CONN* p_data);
 void rw_i93_handle_error(tNFC_STATUS status);
 tNFC_STATUS rw_i93_send_cmd_get_sys_info(uint8_t* p_uid, uint8_t extra_flag);
+tNFC_STATUS rw_i93_send_cmd_get_ext_sys_info(uint8_t* p_uid);
 
 /*******************************************************************************
 **
@@ -141,6 +142,10 @@
       p_i93->product_version = RW_I93_STM_M24LR16E_R;
     else if (p_i93->ic_reference == I93_IC_REF_STM_M24LR64E_R)
       p_i93->product_version = RW_I93_STM_M24LR64E_R;
+    else if (p_i93->ic_reference == I93_IC_REF_STM_ST25DVHIK)
+      p_i93->product_version = RW_I93_STM_ST25DVHIK;
+    else if (p_i93->ic_reference == I93_IC_REF_STM_ST25DV04K)
+      p_i93->product_version = RW_I93_STM_ST25DV04K;
     else {
       switch (p_i93->ic_reference & I93_IC_REF_STM_MASK) {
         case I93_IC_REF_STM_LRI1K:
@@ -187,6 +192,62 @@
 
 /*******************************************************************************
 **
+** Function         rw_i93_process_ext_sys_info
+**
+** Description      Store extended system information of tag
+**
+** Returns          FALSE if retrying with protocol extension flag
+**
+*******************************************************************************/
+bool rw_i93_process_ext_sys_info(uint8_t* p_data) {
+  uint8_t* p = p_data;
+  tRW_I93_CB* p_i93 = &rw_cb.tcb.i93;
+  uint8_t uid[I93_UID_BYTE_LEN], *p_uid;
+
+  DLOG_IF(INFO, nfc_debug_enabled) << __func__;
+
+  STREAM_TO_UINT8(p_i93->info_flags, p);
+
+  p_uid = uid;
+  STREAM_TO_ARRAY8(p_uid, p);
+
+  if (p_i93->info_flags & I93_INFO_FLAG_DSFID) {
+    STREAM_TO_UINT8(p_i93->dsfid, p);
+  }
+  if (p_i93->info_flags & I93_INFO_FLAG_AFI) {
+    STREAM_TO_UINT8(p_i93->afi, p);
+  }
+  if (p_i93->info_flags & I93_INFO_FLAG_MEM_SIZE) {
+    STREAM_TO_UINT16(p_i93->num_block, p);
+
+    /* it is one less than actual number of bytes */
+    p_i93->num_block += 1;
+
+    STREAM_TO_UINT8(p_i93->block_size, p);
+    /* it is one less than actual number of blocks */
+    p_i93->block_size = (p_i93->block_size & 0x1F) + 1;
+  }
+  if (p_i93->info_flags & I93_INFO_FLAG_IC_REF) {
+    STREAM_TO_UINT8(p_i93->ic_reference, p);
+
+    /* clear existing UID to set product version */
+    p_i93->uid[0] = 0x00;
+
+    /* store UID and get product version */
+    rw_i93_get_product_version(p_uid);
+
+    if (p_i93->uid[0] == I93_UID_FIRST_BYTE) {
+      if (p_i93->uid[1] == I93_UID_IC_MFG_CODE_STM) {
+        /* STM supports more than 2040 bytes */
+        p_i93->intl_flags |= RW_I93_FLAG_EXT_COMMANDS;
+      }
+    }
+  }
+  return true;
+}
+
+/*******************************************************************************
+**
 ** Function         rw_i93_process_sys_info
 **
 ** Description      Store system information of tag
@@ -268,12 +329,20 @@
               return false;
             }
           }
-          return true;
         } else if ((p_i93->product_version == RW_I93_STM_LRI2K) &&
                    (p_i93->ic_reference == 0x21)) {
           /* workaround of byte order in memory size information */
           p_i93->num_block = 64;
           p_i93->block_size = 4;
+        } else if (!(p_i93->info_flags & I93_INFO_FLAG_MEM_SIZE)) {
+          if (!(p_i93->intl_flags & RW_I93_FLAG_EXT_COMMANDS)) {
+            if (rw_i93_send_cmd_get_ext_sys_info(NULL) == NFC_STATUS_OK) {
+              /* STM supports more than 2040 bytes */
+              p_i93->intl_flags |= RW_I93_FLAG_EXT_COMMANDS;
+
+              return false;
+            }
+          }
         }
       }
     }
@@ -366,8 +435,11 @@
       break;
 
     case I93_CMD_READ_SINGLE_BLOCK:
+    case I93_CMD_EXT_READ_SINGLE_BLOCK:
     case I93_CMD_READ_MULTI_BLOCK:
+    case I93_CMD_EXT_READ_MULTI_BLOCK:
     case I93_CMD_GET_MULTI_BLK_SEC:
+    case I93_CMD_EXT_GET_MULTI_BLK_SEC:
 
       /* forward tag data or security status */
       p_buff = (NFC_HDR*)GKI_getbuf((uint16_t)(length + NFC_HDR_SIZE));
@@ -393,8 +465,11 @@
       break;
 
     case I93_CMD_WRITE_SINGLE_BLOCK:
+    case I93_CMD_EXT_WRITE_SINGLE_BLOCK:
     case I93_CMD_LOCK_BLOCK:
+    case I93_CMD_EXT_LOCK_BLOCK:
     case I93_CMD_WRITE_MULTI_BLOCK:
+    case I93_CMD_EXT_WRITE_MULTI_BLOCK:
     case I93_CMD_SELECT:
     case I93_CMD_RESET_TO_READY:
     case I93_CMD_WRITE_AFI:
@@ -431,6 +506,28 @@
       }
       break;
 
+    case I93_CMD_EXT_GET_SYS_INFO:
+
+      if (rw_i93_process_ext_sys_info(p)) {
+        rw_data.i93_sys_info.status = NFC_STATUS_OK;
+        rw_data.i93_sys_info.info_flags = p_i93->info_flags;
+        rw_data.i93_sys_info.dsfid = p_i93->dsfid;
+        rw_data.i93_sys_info.afi = p_i93->afi;
+        rw_data.i93_sys_info.num_block = p_i93->num_block;
+        rw_data.i93_sys_info.block_size = p_i93->block_size;
+        rw_data.i93_sys_info.IC_reference = p_i93->ic_reference;
+
+        memcpy(rw_data.i93_sys_info.uid, p_i93->uid, I93_UID_BYTE_LEN);
+
+        event = RW_I93_SYS_INFO_EVT;
+      } else {
+        /* retrying with protocol extension flag or with extended sys info
+         * command */
+        p_i93->state = RW_I93_STATE_BUSY;
+        return;
+      }
+      break;
+
     default:
       break;
   }
@@ -629,12 +726,17 @@
   UINT8_TO_STREAM(p, flags);
 
   /* Command Code */
-  UINT8_TO_STREAM(p, I93_CMD_READ_SINGLE_BLOCK);
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
+    UINT8_TO_STREAM(p, I93_CMD_EXT_READ_SINGLE_BLOCK);
+  } else {
+    UINT8_TO_STREAM(p, I93_CMD_READ_SINGLE_BLOCK);
+  }
 
   /* Parameters */
   ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
 
-  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK) {
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK ||
+      rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
     UINT16_TO_STREAM(p, block_number); /* Block number */
     p_cmd->len++;
   } else {
@@ -642,7 +744,10 @@
   }
 
   if (rw_i93_send_to_lower(p_cmd)) {
-    rw_cb.tcb.i93.sent_cmd = I93_CMD_READ_SINGLE_BLOCK;
+    if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS)
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_EXT_READ_SINGLE_BLOCK;
+    else
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_READ_SINGLE_BLOCK;
     return NFC_STATUS_OK;
   } else {
     return NFC_STATUS_FAILED;
@@ -695,12 +800,17 @@
   UINT8_TO_STREAM(p, flags);
 
   /* Command Code */
-  UINT8_TO_STREAM(p, I93_CMD_WRITE_SINGLE_BLOCK);
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
+    UINT8_TO_STREAM(p, I93_CMD_EXT_WRITE_SINGLE_BLOCK);
+  } else {
+    UINT8_TO_STREAM(p, I93_CMD_WRITE_SINGLE_BLOCK);
+  }
 
   /* Parameters */
   ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
 
-  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK) {
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK ||
+      rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
     UINT16_TO_STREAM(p, block_number); /* Block number */
     p_cmd->len++;
   } else {
@@ -711,7 +821,10 @@
   ARRAY_TO_STREAM(p, p_data, rw_cb.tcb.i93.block_size);
 
   if (rw_i93_send_to_lower(p_cmd)) {
-    rw_cb.tcb.i93.sent_cmd = I93_CMD_WRITE_SINGLE_BLOCK;
+    if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS)
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_EXT_WRITE_SINGLE_BLOCK;
+    else
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_WRITE_SINGLE_BLOCK;
     return NFC_STATUS_OK;
   } else {
     return NFC_STATUS_FAILED;
@@ -761,14 +874,27 @@
   }
 
   /* Command Code */
-  UINT8_TO_STREAM(p, I93_CMD_LOCK_BLOCK);
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
+    UINT8_TO_STREAM(p, I93_CMD_EXT_LOCK_BLOCK);
+  } else {
+    UINT8_TO_STREAM(p, I93_CMD_LOCK_BLOCK);
+  }
 
   /* Parameters */
   ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
-  UINT8_TO_STREAM(p, block_number);       /* Block number */
+
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
+    UINT16_TO_STREAM(p, block_number); /* Block number */
+    p_cmd->len++;
+  } else {
+    UINT8_TO_STREAM(p, block_number); /* Block number */
+  }
 
   if (rw_i93_send_to_lower(p_cmd)) {
-    rw_cb.tcb.i93.sent_cmd = I93_CMD_LOCK_BLOCK;
+    if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS)
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_EXT_LOCK_BLOCK;
+    else
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_LOCK_BLOCK;
     return NFC_STATUS_OK;
   } else {
     return NFC_STATUS_FAILED;
@@ -806,29 +932,44 @@
   flags =
       (I93_FLAG_ADDRESS_SET | RW_I93_FLAG_SUB_CARRIER | RW_I93_FLAG_DATA_RATE);
 
-  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK)
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK) {
     flags |= I93_FLAG_PROT_EXT_YES;
+  }
 
   UINT8_TO_STREAM(p, flags);
 
   /* Command Code */
-  UINT8_TO_STREAM(p, I93_CMD_READ_MULTI_BLOCK);
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
+    UINT8_TO_STREAM(p, I93_CMD_EXT_READ_MULTI_BLOCK);
+  } else {
+    UINT8_TO_STREAM(p, I93_CMD_READ_MULTI_BLOCK);
+  }
 
   /* Parameters */
   ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
 
-  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK) {
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK ||
+      rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
     UINT16_TO_STREAM(p, first_block_number); /* First block number */
     p_cmd->len++;
   } else {
     UINT8_TO_STREAM(p, first_block_number); /* First block number */
   }
 
-  UINT8_TO_STREAM(
-      p, number_blocks - 1); /* Number of blocks, 0x00 to read one block */
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
+    UINT16_TO_STREAM(
+        p, number_blocks - 1); /* Number of blocks, 0x00 to read one block */
+    p_cmd->len++;
+  } else {
+    UINT8_TO_STREAM(
+        p, number_blocks - 1); /* Number of blocks, 0x00 to read one block */
+  }
 
   if (rw_i93_send_to_lower(p_cmd)) {
-    rw_cb.tcb.i93.sent_cmd = I93_CMD_READ_MULTI_BLOCK;
+    if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS)
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_EXT_READ_MULTI_BLOCK;
+    else
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_READ_MULTI_BLOCK;
     return NFC_STATUS_OK;
   } else {
     return NFC_STATUS_FAILED;
@@ -844,7 +985,7 @@
 ** Returns          tNFC_STATUS
 **
 *******************************************************************************/
-tNFC_STATUS rw_i93_send_cmd_write_multi_blocks(uint8_t first_block_number,
+tNFC_STATUS rw_i93_send_cmd_write_multi_blocks(uint16_t first_block_number,
                                                uint16_t number_blocks,
                                                uint8_t* p_data) {
   NFC_HDR* p_cmd;
@@ -868,11 +1009,25 @@
                       RW_I93_FLAG_DATA_RATE));
 
   /* Command Code */
-  UINT8_TO_STREAM(p, I93_CMD_WRITE_MULTI_BLOCK);
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
+    INT8_TO_STREAM(p, I93_CMD_EXT_WRITE_MULTI_BLOCK);
+  } else {
+    UINT8_TO_STREAM(p, I93_CMD_WRITE_MULTI_BLOCK);
+  }
 
   /* Parameters */
   ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
-  UINT8_TO_STREAM(p, first_block_number); /* First block number */
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
+    UINT16_TO_STREAM(p, first_block_number); /* Block number */
+    UINT16_TO_STREAM(
+        p, number_blocks - 1); /* Number of blocks, 0x00 to read one block */
+    p_cmd->len += 2;
+  } else {
+    UINT8_TO_STREAM(p, first_block_number); /* Block number */
+    UINT8_TO_STREAM(
+        p, number_blocks - 1); /* Number of blocks, 0x00 to read one block */
+  }
+
   UINT8_TO_STREAM(
       p, number_blocks - 1); /* Number of blocks, 0x00 to read one block */
 
@@ -880,7 +1035,10 @@
   ARRAY_TO_STREAM(p, p_data, number_blocks * rw_cb.tcb.i93.block_size);
 
   if (rw_i93_send_to_lower(p_cmd)) {
-    rw_cb.tcb.i93.sent_cmd = I93_CMD_WRITE_MULTI_BLOCK;
+    if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS)
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_EXT_WRITE_MULTI_BLOCK;
+    else
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_WRITE_MULTI_BLOCK;
     return NFC_STATUS_OK;
   } else {
     return NFC_STATUS_FAILED;
@@ -1155,6 +1313,59 @@
 
 /*******************************************************************************
 **
+** Function         rw_i93_send_cmd_get_ext_sys_info
+**
+** Description      Send Get Extended System Information Request to VICC
+**
+** Returns          tNFC_STATUS
+**
+*******************************************************************************/
+tNFC_STATUS rw_i93_send_cmd_get_ext_sys_info(uint8_t* p_uid) {
+  NFC_HDR* p_cmd;
+  uint8_t* p;
+
+  DLOG_IF(INFO, nfc_debug_enabled) << __func__;
+
+  p_cmd = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);
+
+  if (!p_cmd) {
+    DLOG_IF(INFO, nfc_debug_enabled) << __func__ << "Cannot allocate buffer";
+    return NFC_STATUS_NO_BUFFERS;
+  }
+
+  p_cmd->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
+  p_cmd->len = 11;
+  p = (uint8_t*)(p_cmd + 1) + p_cmd->offset;
+
+  /* Flags */
+  UINT8_TO_STREAM(p, (I93_FLAG_ADDRESS_SET | RW_I93_FLAG_SUB_CARRIER |
+                      RW_I93_FLAG_DATA_RATE));
+
+  /* Command Code */
+  UINT8_TO_STREAM(p, I93_CMD_EXT_GET_SYS_INFO);
+
+  /* Parameters request field */
+  UINT8_TO_STREAM(p,
+                  (I93_INFO_FLAG_MOI | I93_INFO_FLAG_DSFID | I93_INFO_FLAG_AFI |
+                   I93_INFO_FLAG_MEM_SIZE | I93_INFO_FLAG_IC_REF));
+
+  /* Parameters */
+  if (p_uid) {
+    ARRAY8_TO_STREAM(p, p_uid); /* UID */
+  } else {
+    ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
+  }
+
+  if (rw_i93_send_to_lower(p_cmd)) {
+    rw_cb.tcb.i93.sent_cmd = I93_CMD_EXT_GET_SYS_INFO;
+    return NFC_STATUS_OK;
+  } else {
+    return NFC_STATUS_FAILED;
+  }
+}
+
+/*******************************************************************************
+**
 ** Function         rw_i93_send_cmd_get_sys_info
 **
 ** Description      Send Get System Information Request to VICC
@@ -1238,12 +1449,17 @@
   UINT8_TO_STREAM(p, flags);
 
   /* Command Code */
-  UINT8_TO_STREAM(p, I93_CMD_GET_MULTI_BLK_SEC);
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
+    UINT8_TO_STREAM(p, I93_CMD_EXT_GET_MULTI_BLK_SEC);
+  } else {
+    UINT8_TO_STREAM(p, I93_CMD_GET_MULTI_BLK_SEC);
+  }
 
   /* Parameters */
   ARRAY8_TO_STREAM(p, rw_cb.tcb.i93.uid); /* UID */
 
-  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK) {
+  if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_16BIT_NUM_BLOCK ||
+      rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS) {
     UINT16_TO_STREAM(p, first_block_number); /* First block number */
     UINT16_TO_STREAM(
         p, number_blocks - 1); /* Number of blocks, 0x00 to read one block */
@@ -1255,7 +1471,10 @@
   }
 
   if (rw_i93_send_to_lower(p_cmd)) {
-    rw_cb.tcb.i93.sent_cmd = I93_CMD_GET_MULTI_BLK_SEC;
+    if (rw_cb.tcb.i93.intl_flags & RW_I93_FLAG_EXT_COMMANDS)
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_EXT_GET_MULTI_BLK_SEC;
+    else
+      rw_cb.tcb.i93.sent_cmd = I93_CMD_GET_MULTI_BLK_SEC;
     return NFC_STATUS_OK;
   } else {
     return NFC_STATUS_FAILED;
@@ -1345,6 +1564,8 @@
   if (num_blocks > RW_I93_GET_MULTI_BLOCK_SEC_SIZE)
     num_blocks = RW_I93_GET_MULTI_BLOCK_SEC_SIZE;
 
+  DLOG_IF(INFO, nfc_debug_enabled)
+      << __func__ << std::hex << rw_cb.tcb.i93.intl_flags;
   return rw_i93_send_cmd_get_multi_block_sec(p_i93->rw_offset, num_blocks);
 }
 
@@ -1469,9 +1690,8 @@
           << StringPrintf("Total blocks:0x%04X, Block size:0x%02X",
                           p_i93->num_block, p_i93->block_size);
 
-      if ((cc[0] == I93_ICODE_CC_MAGIC_NUMER) &&
-          ((cc[3] & I93_STM_CC_OVERFLOW_MASK) ||
-           (cc[2] * 8) == (p_i93->num_block * p_i93->block_size))) {
+      if ((cc[0] == I93_ICODE_CC_MAGIC_NUMER_E1) ||
+          (cc[0] == I93_ICODE_CC_MAGIC_NUMER_E2)) {
         if ((cc[1] & I93_ICODE_CC_READ_ACCESS_MASK) ==
             I93_ICODE_CC_READ_ACCESS_GRANTED) {
           if ((cc[1] & I93_ICODE_CC_WRITE_ACCESS_MASK) !=
@@ -1483,6 +1703,9 @@
             /* tag supports read multi blocks command */
             p_i93->intl_flags |= RW_I93_FLAG_READ_MULTI_BLOCK;
           }
+          if (cc[0] == I93_ICODE_CC_MAGIC_NUMER_E2) {
+            p_i93->intl_flags |= RW_I93_FLAG_EXT_COMMANDS;
+          }
           status = NFC_STATUS_OK;
         }
       }
@@ -2318,7 +2541,7 @@
       p = p_i93->p_update_data;
 
       /* Capability Container */
-      *(p++) = I93_ICODE_CC_MAGIC_NUMER; /* magic number */
+      *(p++) = I93_ICODE_CC_MAGIC_NUMER_E1; /* magic number */
       *(p++) = 0x40;                     /* version 1.0, read/write */
 
       /* if memory size is less than 2048 bytes */
@@ -3051,7 +3274,7 @@
 **                  NFC_STATUS_FAILED if other error
 **
 *******************************************************************************/
-tNFC_STATUS RW_I93WriteMultipleBlocks(uint8_t first_block_number,
+tNFC_STATUS RW_I93WriteMultipleBlocks(uint16_t first_block_number,
                                       uint16_t number_blocks, uint8_t* p_data) {
   tNFC_STATUS status;
 
@@ -3783,6 +4006,10 @@
       return "M24LR16E";
     case RW_I93_STM_M24LR64E_R:
       return "M24LR64E";
+    case RW_I93_STM_ST25DV04K:
+      return "ST25DV04";
+    case RW_I93_STM_ST25DVHIK:
+      return "ST25DV";
     case RW_I93_UNKNOWN_PRODUCT:
     default:
       return "UNKNOWN";