recovery_seq.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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. #include "recovery_seq.h"
  20. struct recovery_info g_recovery_info;
  21. struct recovery_frame g_recovery_frame;
  22. /** @brief Function to calculate crc value.
  23. *
  24. * @param pbuffer: input buffer for crc calculation.
  25. * dwLength: length of input buffer
  26. * @return calculated uint16_t crc valueof input buffer.
  27. */
  28. static uint16_t calcCrc16(uint8_t *pbuffer, uint32_t dwLength)
  29. {
  30. uint32_t i = 0;
  31. uint16_t crc_new = 0;
  32. uint16_t crc = DL_INVALID_CRC_VALUE;
  33. if (pbuffer == NULL) {
  34. pr_err("%s, invalid params", __func__);
  35. return crc;
  36. }
  37. for (i = 0; i < dwLength; i++) {
  38. crc_new = (uint8_t)(crc >> MSB_POS) | (crc << MSB_POS);
  39. crc_new ^= pbuffer[i];
  40. crc_new ^= (uint8_t)(crc_new & DL_CRC_MASK) >> 4;
  41. crc_new ^= crc_new << 12;
  42. crc_new ^= (crc_new & DL_CRC_MASK) << 5;
  43. crc = crc_new;
  44. }
  45. return crc;
  46. }
  47. /** @brief Function to build command frame for recover.
  48. *
  49. * @return status code of recovery_status type.
  50. */
  51. static enum recovery_status build_cmd_frame(void)
  52. {
  53. uint16_t len = 0;
  54. uint16_t wCrc = 0;
  55. uint16_t writeOffset = 0;
  56. pr_debug(" %s Entry", __func__);
  57. if (gphDnldNfc_DlSeqSz == 0) {
  58. pr_err(" %s invalid params", __func__);
  59. return STATUS_FAILED;
  60. }
  61. memset(g_recovery_frame.p_buffer, 0x00, MAX_FRAME_SIZE);
  62. g_recovery_frame.len = 0;
  63. if (g_recovery_info.bFrameSegmented == false) {
  64. len = gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset];
  65. len <<= MSB_POS;
  66. len |= gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset + 1];
  67. } else {
  68. /* last frame was segmented frame
  69. * read length reamaining length
  70. */
  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. */
  102. len += FW_HDR_LEN;
  103. }
  104. g_recovery_info.wRemChunkBytes = 0;
  105. g_recovery_info.bFrameSegmented = false;
  106. }
  107. if (((writeOffset + len) > MAX_FRAME_SIZE) ||
  108. ((g_recovery_info.currentReadOffset + len) > gphDnldNfc_DlSeqSz)) {
  109. pr_err("%s frame offsets out of bound", __func__);
  110. return STATUS_FAILED;
  111. }
  112. memcpy(&g_recovery_frame.p_buffer[writeOffset],
  113. &gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset], len);
  114. g_recovery_info.currentReadOffset += len;
  115. g_recovery_frame.len += len;
  116. writeOffset += len;
  117. g_recovery_info.remBytes -= len;
  118. wCrc = calcCrc16(g_recovery_frame.p_buffer,
  119. g_recovery_frame.len);
  120. g_recovery_frame.p_buffer[writeOffset++] = (wCrc >> MSB_POS) & SHIFT_MASK;
  121. g_recovery_frame.p_buffer[writeOffset++] = wCrc & SHIFT_MASK;
  122. g_recovery_frame.len += FW_CRC_LEN;
  123. return STATUS_SUCCESS;
  124. }
  125. /** @brief Function to transmit recovery frame.
  126. * @param nfc_dev nfc driver object.
  127. * @return status code of recovery_status type.
  128. */
  129. static enum recovery_status transmit(struct nfc_dev *nfc_dev)
  130. {
  131. int ret = 0;
  132. int frame_resp_len = 0;
  133. uint16_t respCRC = 0;
  134. uint16_t respCRCOffset = 0;
  135. uint8_t *rsp_buf = nfc_dev->read_kbuf;
  136. pr_debug("%s Entry", __func__);
  137. if (nfc_dev == NULL || g_recovery_frame.len <= 0) {
  138. pr_err("%s invalid Params", __func__);
  139. return STATUS_FAILED;
  140. }
  141. ret = nfc_dev->nfc_write(nfc_dev, g_recovery_frame.p_buffer,
  142. g_recovery_frame.len, MAX_RETRY_COUNT);
  143. if (ret <= 0) {
  144. pr_err(" %s: Write recovery frame error %d\n", __func__, ret);
  145. return STATUS_FAILED;
  146. }
  147. pr_debug(" %s Reading response\n", __func__);
  148. memset(rsp_buf, 0x00, MAX_BUFFER_SIZE);
  149. ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, FW_HDR_LEN, NCI_CMD_RSP_TIMEOUT);
  150. if (ret < FW_HDR_LEN) {
  151. pr_err(" %s - Read recovery frame response error ret %d\n", __func__, ret);
  152. return STATUS_FAILED;
  153. }
  154. if (rsp_buf[0] != FW_MSG_CMD_RSP ||
  155. rsp_buf[DL_FRAME_RESP_LEN_OFFSET] != DL_FRAME_RESP_LEN) {
  156. pr_err("%s, invalid response", __func__);
  157. return STATUS_FAILED;
  158. }
  159. frame_resp_len = rsp_buf[DL_FRAME_RESP_LEN_OFFSET] + FW_CRC_LEN;
  160. ret = nfc_dev->nfc_read(nfc_dev, rsp_buf + FW_HDR_LEN, frame_resp_len, NCI_CMD_RSP_TIMEOUT);
  161. if (ret < frame_resp_len) {
  162. pr_err(" %s - Read recovery frame response error ret %d\n", __func__, ret);
  163. return STATUS_FAILED;
  164. }
  165. pr_debug(" %s: recovery frame Response 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
  166. __func__, rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5]);
  167. respCRCOffset = FW_HDR_LEN + rsp_buf[DL_FRAME_RESP_LEN_OFFSET];
  168. respCRC = rsp_buf[respCRCOffset++];
  169. respCRC <<= MSB_POS;
  170. respCRC |= rsp_buf[respCRCOffset];
  171. if (respCRC != calcCrc16(rsp_buf, DL_FRAME_RESP_LEN + FW_HDR_LEN)) {
  172. pr_err("%s, invalid response crc", __func__);
  173. return STATUS_FAILED;
  174. }
  175. if (g_recovery_info.bFrameSegmented &&
  176. (rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT1
  177. && rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT2)) {
  178. pr_err("%s, invalid stat flag in chunk response", __func__);
  179. return STATUS_FAILED;
  180. }
  181. if (!g_recovery_info.bFrameSegmented &&
  182. rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_NON_SEGMENTED_FRAME_RESP_STAT) {
  183. pr_err("%s, invalid stat flag in response", __func__);
  184. return STATUS_FAILED;
  185. }
  186. return STATUS_SUCCESS;
  187. }
  188. /** @brief Function to check input version with recovery fw version.
  189. * @param fw_major_version: input major_version to check.
  190. * @return true if input major_version matches with recovery fw major version
  191. * otherwise returns false.
  192. */
  193. static bool check_major_version(uint8_t fw_major_version)
  194. {
  195. if (gphDnldNfc_DlSeqSz < RECOVERY_FW_MJ_VER_OFFSET) {
  196. /* Recovery data corrupted */
  197. pr_err("%s Not able to extract major version from recovery fw\n", __func__);
  198. return false;
  199. }
  200. return (fw_major_version == gphDnldNfc_DlSequence[RECOVERY_FW_MJ_VER_OFFSET]);
  201. }
  202. /** @brief Function to recover the nfcc.
  203. * @param nfc_dev nfc driver object.
  204. * @return status code of type recovery_status.
  205. */
  206. enum recovery_status do_recovery(struct nfc_dev *nfc_dev)
  207. {
  208. enum recovery_status status = STATUS_SUCCESS;
  209. g_recovery_info.remBytes = gphDnldNfc_DlSeqSz;
  210. g_recovery_info.currentReadOffset = 0;
  211. g_recovery_info.bFrameSegmented = false;
  212. g_recovery_info.wRemChunkBytes = 0;
  213. g_recovery_frame.p_buffer = nfc_dev->write_kbuf;
  214. pr_debug("%s Entry", __func__);
  215. if (nfc_dev == NULL) {
  216. pr_err("%s invalid params ", __func__);
  217. return STATUS_FAILED;
  218. }
  219. if (!(check_major_version(nfc_dev->fw_major_version))) {
  220. pr_err("%s unsupported version", __func__);
  221. status = STATUS_FAILED;
  222. goto EXIT_RECOVERY;
  223. }
  224. while (g_recovery_info.remBytes > 0) {
  225. status = build_cmd_frame();
  226. if (status != STATUS_SUCCESS) {
  227. pr_err(" %s Unable to create recovery frame");
  228. break;
  229. }
  230. status = transmit(nfc_dev);
  231. if (status != STATUS_SUCCESS) {
  232. pr_err(" %s Unable to send recovery frame");
  233. break;
  234. }
  235. }
  236. EXIT_RECOVERY:
  237. pr_info("%s Recovery done status %d", __func__, status);
  238. return status;
  239. }