1 /*
2  * Copyright (C) 2012-2014 NXP Semiconductors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <phNxpLog.h>
18 #include <phNxpNciHal_Kovio.h>
19 
20 /* Timeout value to wait for RF INTF Activated NTF.*/
21 #define KOVIO_TIMEOUT 1000
22 #define KOVIO_ACT_NTF_TEMP_BUFF_LEN         \
23   64 /* length of temp buffer to manipulate \
24 the activated notification to match BCM format*/
25 #define MAX_WRITE_RETRY 5
26 
27 /******************* Global variables *****************************************/
28 extern phNxpNciHal_Control_t nxpncihal_ctrl;
29 extern NFCSTATUS phNxpNciHal_send_ext_cmd(uint16_t cmd_len, uint8_t* p_cmd);
30 
31 int kovio_detected = 0x00;
32 int send_to_upper_kovio = 0x01;
33 int disable_kovio = 0x00;
34 bool_t rf_deactive_cmd = false;
35 static uint8_t rf_deactivate_cmd[] = {0x21, 0x06, 0x01, 0x03}; /* discovery */
36 static uint8_t rf_deactivated_ntf[] = {0x61, 0x06, 0x02, 0x03, 0x01};
37 static uint8_t reset_ntf[] = {0x60, 0x00, 0x06, 0xA0, 0x00,
38                               0xC7, 0xD4, 0x00, 0x00};
39 
40 static uint32_t kovio_timer;
41 
42 /************** Kovio functions ***************************************/
43 
44 static NFCSTATUS phNxpNciHal_rf_deactivate(void);
45 
46 /*******************************************************************************
47 **
48 ** Function         hal_write_cb
49 **
50 ** Description      Callback function for hal write.
51 **
52 ** Returns          None
53 **
54 *******************************************************************************/
hal_write_cb(void * pContext,phTmlNfc_TransactInfo_t * pInfo)55 static void hal_write_cb(void* pContext, phTmlNfc_TransactInfo_t* pInfo) {
56   UNUSED(pContext);
57   UNUSED(pInfo);
58   return;
59 }
60 
61 /*******************************************************************************
62 **
63 ** Function         kovio_timer_handler
64 **
65 ** Description      Callback function for kovio timer.
66 **
67 ** Returns          None
68 **
69 *******************************************************************************/
kovio_timer_handler(uint32_t timerId,void * pContext)70 static void kovio_timer_handler(uint32_t timerId, void* pContext) {
71   UNUSED(timerId);
72   UNUSED(pContext);
73   NXPLOG_NCIHAL_D(
74       ">> kovio_timer_handler. Did not receive RF_INTF_ACTIVATED_NTF, Kovio "
75       "TAG must be removed.");
76 
77   phOsalNfc_Timer_Delete(kovio_timer);
78 
79   kovio_detected = 0x00;
80   send_to_upper_kovio = 0x01;
81   disable_kovio = 0x00;
82   /*
83    * send kovio deactivated ntf to upper layer.
84   */
85   NXPLOG_NCIHAL_D(">> send kovio deactivated ntf to upper layer.");
86   if (nxpncihal_ctrl.p_nfc_stack_data_cback != NULL) {
87     (*nxpncihal_ctrl.p_nfc_stack_data_cback)(sizeof(rf_deactivated_ntf),
88                                              rf_deactivated_ntf);
89   }
90   return;
91 }
92 
93 /*******************************************************************************
94 **
95 ** Function         phNxpNciHal_rf_deactivate
96 **
97 ** Description      Sends rf deactivate cmd to NFCC
98 **
99 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
100 **
101 *******************************************************************************/
phNxpNciHal_rf_deactivate()102 static NFCSTATUS phNxpNciHal_rf_deactivate() {
103   NFCSTATUS status = NFCSTATUS_SUCCESS;
104   int cb_data;
105   int retryCnt = 0;
106 
107   do {
108     retryCnt++;
109     status = phTmlNfc_Write(rf_deactivate_cmd, sizeof(rf_deactivate_cmd),
110                             (pphTmlNfc_TransactCompletionCb_t)&hal_write_cb,
111                             &cb_data);
112   } while (status != NFCSTATUS_PENDING && retryCnt <= MAX_WRITE_RETRY);
113 
114   if (status != NFCSTATUS_PENDING) {
115     // phNxpNciHal_emergency_recovery();
116     if (nxpncihal_ctrl.p_nfc_stack_data_cback != NULL &&
117         nxpncihal_ctrl.hal_open_status == true) {
118       NXPLOG_NCIHAL_D(
119           "Send the Core Reset NTF to upper layer, which will trigger the "
120           "recovery\n");
121       // Send the Core Reset NTF to upper layer, which will trigger the
122       // recovery.
123       send_to_upper_kovio = 0;
124       nxpncihal_ctrl.rx_data_len = sizeof(reset_ntf);
125       memcpy(nxpncihal_ctrl.p_rx_data, reset_ntf, sizeof(reset_ntf));
126       (*nxpncihal_ctrl.p_nfc_stack_data_cback)(nxpncihal_ctrl.rx_data_len,
127                                                nxpncihal_ctrl.p_rx_data);
128     }
129   }
130 
131   return status;
132 }
133 
134 /*******************************************************************************
135 **
136 ** Function         phNxpNciHal_kovio_rsp_ext
137 **
138 ** Description      Implements kovio presence check. In BCM controller this is
139 **                  managed by NFCC. But since PN54X does not handle this, the
140 **                  presence check is mimiced here.
141 **                  For the very first time Kovio is detected, NTF has to be
142 **                  passed on to upper layer. for every NTF, DH send a
143 **                  deactivated command to NFCC and NFCC follows this up with
144 **                  another activated notification. When the tag is removed,
145 **                  activated notification stops coming and this is indicated to
146 **                  upper layer with a HAL generated deactivated notification.
147 **
148 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
149 **
150 *******************************************************************************/
phNxpNciHal_kovio_rsp_ext(uint8_t * p_ntf,uint16_t * p_len)151 NFCSTATUS phNxpNciHal_kovio_rsp_ext(uint8_t* p_ntf, uint16_t* p_len) {
152   NFCSTATUS status = NFCSTATUS_SUCCESS;
153   uint8_t tBuff[KOVIO_ACT_NTF_TEMP_BUFF_LEN];
154 
155   send_to_upper_kovio = 1;
156   if ((p_ntf[0] == 0x61) && (p_ntf[1] == 0x05)) {
157 #if (NFC_NXP_CHIP_TYPE != PN547C2)
158     if ((p_ntf[5] == 0x81) && (p_ntf[6] == 0x70))
159 #else
160     if ((p_ntf[5] == 0x8A) && (p_ntf[6] == 0x77))
161 #endif
162     {
163       if (kovio_detected == 0) {
164         if ((*p_len - 9) < KOVIO_ACT_NTF_TEMP_BUFF_LEN) {
165           p_ntf[2] += 1;
166           memcpy(tBuff, &p_ntf[9], *p_len - 9);
167           p_ntf[9] = p_ntf[9] + 1;
168           memcpy(&p_ntf[10], tBuff, *p_len - 9);
169           *p_len += 1;
170         } else {
171           NXPLOG_NCIHAL_D("Kovio Act ntf payload exceeded temp buffer size");
172         }
173         kovio_detected = 1;
174         kovio_timer = phOsalNfc_Timer_Create();
175         NXPLOG_NCIHAL_D("custom kovio timer Created - %d", kovio_timer);
176       } else {
177         send_to_upper_kovio = 0;
178       }
179 
180       if (!rf_deactive_cmd) {
181         NXPLOG_NCIHAL_D("Send RF deactivate command to NFCC");
182         status = phNxpNciHal_rf_deactivate();
183       } else {
184         NXPLOG_NCIHAL_D("RF deactivate command is already sent to NFCC");
185         disable_kovio = true;
186         send_to_upper_kovio = 0;
187       }
188       status = phOsalNfc_Timer_Start(kovio_timer, KOVIO_TIMEOUT,
189                                      &kovio_timer_handler, NULL);
190       if (NFCSTATUS_SUCCESS == status) {
191         NXPLOG_NCIHAL_D("kovio timer started");
192       } else {
193         NXPLOG_NCIHAL_E("kovio timer not started!!!");
194         status = NFCSTATUS_FAILED;
195       }
196     } else {
197       if (kovio_detected == 1) {
198         phNxpNciHal_clean_Kovio_Ext();
199         NXPLOG_NCIHAL_D(
200             "Disabling Kovio detection logic as another tag type detected");
201       }
202     }
203   } else if ((p_ntf[0] == 0x41) && (p_ntf[1] == 0x06) && (p_ntf[2] == 0x01)) {
204     rf_deactive_cmd = false;
205     if (kovio_detected == 1) send_to_upper_kovio = 0;
206     if ((kovio_detected == 1) && (disable_kovio == 0x01)) {
207       NXPLOG_NCIHAL_D("Disabling Kovio detection logic");
208       phNxpNciHal_clean_Kovio_Ext();
209       disable_kovio = 0x00;
210     }
211   } else if ((p_ntf[0] == 0x61) && (p_ntf[1] == 0x06) && (p_ntf[2] == 0x02) &&
212              (p_ntf[3] == 0x03) && (p_ntf[4] == 0x00)) {
213     if (kovio_detected == 1) send_to_upper_kovio = 0;
214   } else if ((p_ntf[0] == 0x61) && (p_ntf[1] == 0x03)) {
215     if (kovio_detected == 1) send_to_upper_kovio = 0;
216   }
217   return status;
218 }
219 /*******************************************************************************
220 **
221 ** Function         phNxpNciHal_clean_Kovio_Ext
222 **
223 ** Description      Clean up Kovio extension state machine.
224 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
225 **
226 *******************************************************************************/
phNxpNciHal_clean_Kovio_Ext()227 void phNxpNciHal_clean_Kovio_Ext() {
228   NXPLOG_NCIHAL_D(">> Cleaning up Kovio State machine and timer.");
229   phOsalNfc_Timer_Delete(kovio_timer);
230   kovio_detected = 0x00;
231   send_to_upper_kovio = 0x01;
232   disable_kovio = 0x00;
233   /*
234    * send kovio deactivated ntf to upper layer.
235   */
236   NXPLOG_NCIHAL_D(">> send kovio deactivated ntf to upper layer.");
237   if (nxpncihal_ctrl.p_nfc_stack_data_cback != NULL) {
238     (*nxpncihal_ctrl.p_nfc_stack_data_cback)(sizeof(rf_deactivated_ntf),
239                                              rf_deactivated_ntf);
240   }
241   return;
242 }
243