recovery_seq.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /******************************************************************************
  2. * Copyright (C) 2021 NXP
  3. * *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. ******************************************************************************/
  19. #if defined(RECOVERY_ENABLE)
  20. #include "recovery_seq.h"
  21. recovery_info_t g_recovery_info;
  22. recovery_frame_t g_recovery_frame;
  23. extern const uint32_t gphDnldNfc_DlSeqSz; /* Recovery user buffer size */
  24. extern const uint8_t gphDnldNfc_DlSequence[]; /* Recovery user buffer */
  25. /** @brief Function to calculate crc value.
  26. *
  27. * @param pbuffer: input buffer for crc calculation.
  28. * dwLength: length of input buffer
  29. * @return calculated uint16_t crc valueof input buffer.
  30. */
  31. static uint16_t calcCrc16(uint8_t* pbuffer, uint32_t dwLength) {
  32. uint32_t i = 0;
  33. uint16_t crc_new = 0;
  34. uint16_t crc = DL_INVALID_CRC_VALUE;
  35. if(NULL == pbuffer) {
  36. pr_err("%s, invalid params", __func__);
  37. return crc;
  38. }
  39. for (i = 0; i < dwLength; i++) {
  40. crc_new = (uint8_t)(crc >> MSB_POS) | (crc << MSB_POS );
  41. crc_new ^= pbuffer[i];
  42. crc_new ^= (uint8_t)(crc_new & DL_CRC_MASK) >> 4;
  43. crc_new ^= crc_new << 12;
  44. crc_new ^= (crc_new & DL_CRC_MASK) << 5;
  45. crc = crc_new;
  46. }
  47. return crc;
  48. }
  49. /** @brief Function to build command frame for recover.
  50. *
  51. * @return status code of recovery_status_t type.
  52. */
  53. static recovery_status_t build_cmd_frame() {
  54. uint16_t len = 0;
  55. uint16_t wCrc = 0;
  56. uint16_t writeOffset = 0;
  57. pr_debug(" %s Entry", __func__);
  58. if(gphDnldNfc_DlSeqSz == 0) {
  59. pr_err(" %s invalid params", __func__);
  60. return STATUS_FAILED;
  61. }
  62. memset(g_recovery_frame.p_buffer, 0x00, MAX_FRAME_SIZE);
  63. g_recovery_frame.len = 0;
  64. if(g_recovery_info.bFrameSegmented == false) {
  65. len = gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset];
  66. len <<= MSB_POS;
  67. len |= gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset + 1];
  68. } else {
  69. /* last frame was segmented frame
  70. * read length reamaining length */
  71. len = g_recovery_info.wRemChunkBytes;
  72. }
  73. if(len > MAX_DATA_SIZE) {
  74. /* set remaining chunk */
  75. g_recovery_info.wRemChunkBytes = (len - MAX_DATA_SIZE);
  76. len = MAX_DATA_SIZE;
  77. /* set chunk bit to write in header */
  78. len = DL_SET_HDR_FRAGBIT(len);
  79. g_recovery_frame.p_buffer[writeOffset++] = (len >> MSB_POS) & SHIFT_MASK;
  80. g_recovery_frame.p_buffer[writeOffset++] = len & SHIFT_MASK;
  81. /* clear chunk bit for length variable */
  82. len = DL_CLR_HDR_FRAGBIT(len);
  83. /* first chunk of segmented frame*/
  84. if(!g_recovery_info.bFrameSegmented) {
  85. /* ignore header from user buffer */
  86. g_recovery_info.currentReadOffset += FW_HDR_LEN;
  87. g_recovery_info.remBytes -= FW_HDR_LEN;
  88. }
  89. g_recovery_frame.len += FW_HDR_LEN;
  90. g_recovery_info.bFrameSegmented = true;
  91. } else {
  92. /* last chunk of segmented frame */
  93. if(g_recovery_info.bFrameSegmented) {
  94. /* write header with user chunk length */
  95. g_recovery_frame.p_buffer[writeOffset++] = (len >> MSB_POS) & SHIFT_MASK;
  96. g_recovery_frame.p_buffer[writeOffset++] = len & SHIFT_MASK;
  97. g_recovery_frame.len += FW_HDR_LEN;
  98. } else {
  99. /* normal Frame with in supported size increase
  100. * len to read header from user data */
  101. len += FW_HDR_LEN;
  102. }
  103. g_recovery_info.wRemChunkBytes = 0;
  104. g_recovery_info.bFrameSegmented = false;
  105. }
  106. if(((writeOffset + len) > MAX_FRAME_SIZE) ||
  107. ((g_recovery_info.currentReadOffset + len) > gphDnldNfc_DlSeqSz)) {
  108. pr_err("%s frame offsets out of bound",__func__);
  109. return STATUS_FAILED;
  110. }
  111. memcpy(&g_recovery_frame.p_buffer[writeOffset],
  112. &gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset], len);
  113. g_recovery_info.currentReadOffset += len;
  114. g_recovery_frame.len += len;
  115. writeOffset += len;
  116. g_recovery_info.remBytes -= len;
  117. wCrc = calcCrc16(g_recovery_frame.p_buffer,
  118. g_recovery_frame.len);
  119. g_recovery_frame.p_buffer[writeOffset++] = (wCrc >> MSB_POS) & SHIFT_MASK;
  120. g_recovery_frame.p_buffer[writeOffset++] = wCrc & SHIFT_MASK;
  121. g_recovery_frame.len += FW_CRC_LEN;
  122. return STATUS_SUCCESS;
  123. }
  124. /** @brief Function to tramsmit recovery frame.
  125. * @param nfc_dev nfc driver object.
  126. * @return status code of recovery_status_t type.
  127. */
  128. static recovery_status_t transmit(nfc_dev_t* nfc_dev) {
  129. char rsp_buf[MAX_BUFFER_SIZE];
  130. int ret = 0;
  131. int frame_resp_len = 0;
  132. uint16_t respCRC = 0;
  133. uint16_t respCRCOffset = 0;
  134. pr_debug("%s Entry", __func__);
  135. if(NULL == nfc_dev || g_recovery_frame.len <= 0) {
  136. pr_err("%s invalid Params ", __func__);
  137. return STATUS_FAILED;
  138. }
  139. ret = nfc_dev->nfc_write(nfc_dev, g_recovery_frame.p_buffer,
  140. g_recovery_frame.len, MAX_RETRY_COUNT);
  141. if (ret <= 0) {
  142. pr_err(" %s: Write recovery frame error %d\n", __func__, ret);
  143. return STATUS_FAILED;
  144. }
  145. pr_debug(" %s Reading response \n", __func__);
  146. memset(rsp_buf, 0x00, MAX_BUFFER_SIZE);
  147. ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, FW_HDR_LEN, NCI_CMD_RSP_TIMEOUT);
  148. if (ret < FW_HDR_LEN) {
  149. pr_err(" %s - Read recovery frame response error ret %d\n", __func__, ret);
  150. return STATUS_FAILED;
  151. }
  152. if( rsp_buf[0] != FW_MSG_CMD_RSP ||
  153. rsp_buf[DL_FRAME_RESP_LEN_OFFSET] != DL_FRAME_RESP_LEN) {
  154. pr_err("%s, invalid response", __func__);
  155. return STATUS_FAILED;
  156. }
  157. frame_resp_len = rsp_buf[DL_FRAME_RESP_LEN_OFFSET] + FW_CRC_LEN;
  158. ret = nfc_dev->nfc_read(nfc_dev, rsp_buf + FW_HDR_LEN, frame_resp_len, NCI_CMD_RSP_TIMEOUT);
  159. if (ret < frame_resp_len) {
  160. pr_err(" %s - Read recovery frame response error ret %d\n", __func__, ret);
  161. return STATUS_FAILED;
  162. }
  163. pr_debug(" %s: recovery frame Response 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
  164. __func__, rsp_buf[0], rsp_buf[1],rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5]);
  165. respCRCOffset = FW_HDR_LEN + rsp_buf[DL_FRAME_RESP_LEN_OFFSET];
  166. respCRC = rsp_buf[respCRCOffset++];
  167. respCRC <<= MSB_POS;
  168. respCRC |= rsp_buf[respCRCOffset];
  169. if(respCRC != calcCrc16(rsp_buf, DL_FRAME_RESP_LEN + FW_HDR_LEN)) {
  170. pr_err("%s, invalid response crc", __func__);
  171. return STATUS_FAILED;
  172. }
  173. if(g_recovery_info.bFrameSegmented &&
  174. (rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT1
  175. && rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT2)) {
  176. pr_err("%s, invalid stat flag in chunk response", __func__);
  177. return STATUS_FAILED;
  178. }
  179. if(!g_recovery_info.bFrameSegmented &&
  180. rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_NON_SEGMENTED_FRAME_RESP_STAT) {
  181. pr_err("%s, invalid stat flag in response", __func__);
  182. return STATUS_FAILED;
  183. }
  184. return STATUS_SUCCESS;
  185. }
  186. /** @brief Function to detect the fw state and print.
  187. * @param nfc_dev nfc driver object.
  188. * @return no return.
  189. */
  190. static void detect_fw_state(nfc_dev_t* nfc_dev) {
  191. const char get_session_state_cmd[] = { 0x00, 0x04, 0xF2, 0x00, 0x00, 0x00, 0xF5, 0x33 };
  192. char rsp_buf[MAX_BUFFER_SIZE];
  193. int ret = 0;
  194. pr_debug("%s:Sending GET_SESSION_STATE cmd \n", __func__);
  195. ret = nfc_dev->nfc_write(nfc_dev, get_session_state_cmd,
  196. sizeof(get_session_state_cmd), MAX_RETRY_COUNT);
  197. if (ret <= 0) {
  198. pr_err("%s: - nfc get session state cmd err ret %d\n", __func__, ret);
  199. return;
  200. }
  201. memset(rsp_buf, 0x00, DL_GET_SESSION_STATE_RSP_LEN);
  202. pr_debug("%s: Reading response of GET_SESSION_STATE cmd\n", __func__);
  203. ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT);
  204. if (ret <= 0) {
  205. pr_err("%s: - nfc get session state rsp err %d\n", __func__, ret);
  206. return;
  207. }
  208. pr_debug("Response bytes are %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x",
  209. rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5],
  210. rsp_buf[6], rsp_buf[7]);
  211. /*verify fw in non-teared state */
  212. if (rsp_buf[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) {
  213. pr_err("%s NFCC is in teared state %d\n", __func__, __LINE__);
  214. } else {
  215. pr_info("%s NFCC is in recoverd state %d\n", __func__, __LINE__);
  216. }
  217. }
  218. /** @brief Function to check input version with recovery fw version.
  219. * @param fw_major_version: input major_version to check.
  220. * @return true if input major_version matches with recovery fw major version
  221. * otherwise returns false.
  222. */
  223. static bool check_major_version(uint8_t fw_major_version) {
  224. if(gphDnldNfc_DlSeqSz < RECOVERY_FW_MJ_VER_OFFSET) {
  225. /* Recovery data corrupted */
  226. pr_err("%s Not able to extract major version from recovery fw\n", __func__);
  227. return false;
  228. }
  229. return (fw_major_version == gphDnldNfc_DlSequence[RECOVERY_FW_MJ_VER_OFFSET]);
  230. }
  231. /** @brief Function to recover the nfcc.
  232. * @param nfc_dev nfc driver object.
  233. * @return status code of type recovery_status_t.
  234. */
  235. recovery_status_t do_recovery(nfc_dev_t *nfc_dev) {
  236. recovery_status_t status = STATUS_SUCCESS;
  237. g_recovery_info.remBytes = gphDnldNfc_DlSeqSz;
  238. g_recovery_info.currentReadOffset = 0;
  239. g_recovery_info.bFrameSegmented = false;
  240. g_recovery_info.wRemChunkBytes = 0;
  241. pr_debug("%s Entry", __func__);
  242. if(NULL == nfc_dev) {
  243. pr_err("%s invalid params ", __func__);
  244. return STATUS_FAILED;
  245. }
  246. if(!nfc_dev->recovery_required
  247. || !(check_major_version(nfc_dev->fw_major_version))) {
  248. pr_err("%s recovery not required or unsupported version", __func__);
  249. status = STATUS_FAILED;
  250. goto EXIT_RECOVERY;
  251. }
  252. while(g_recovery_info.remBytes > 0) {
  253. status = build_cmd_frame();
  254. if(status != STATUS_SUCCESS) {
  255. pr_err(" %s Unable to create recovery frame");
  256. break;
  257. }
  258. status = transmit(nfc_dev);
  259. if(status != STATUS_SUCCESS) {
  260. pr_err(" %s Unable to send recovery frame");
  261. break;
  262. }
  263. }
  264. EXIT_RECOVERY:
  265. detect_fw_state(nfc_dev);
  266. /*set NCI mode for i2c products with dwl pin */
  267. enable_dwnld_mode(nfc_dev, false);
  268. pr_info("%s Recovery done status %d", __func__, status);
  269. return status;
  270. }
  271. #endif