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 <phNxpNciHal_Kovio.h>
18 #include <phNxpLog.h>
19 
20 
21 #define KOVIO_TIMEOUT 1000    /* Timeout value to wait for RF INTF Activated NTF.*/
22 #define KOVIO_ACT_NTF_TEMP_BUFF_LEN 64    /* length of temp buffer to manipulate
23                                     the activated notification to match BCM format*/
24 #define MAX_WRITE_RETRY 5
25 
26 /******************* Global variables *****************************************/
27 extern phNxpNciHal_Control_t nxpncihal_ctrl;
28 extern NFCSTATUS phNxpNciHal_send_ext_cmd(uint16_t cmd_len, uint8_t *p_cmd);
29 
30 int kovio_detected = 0x00;
31 int send_to_upper_kovio = 0x01;
32 int disable_kovio=0x00;
33 bool_t rf_deactive_cmd = FALSE;
34 static uint8_t rf_deactivate_cmd[]   = { 0x21, 0x06, 0x01, 0x03 }; /* discovery */
35 static uint8_t rf_deactivated_ntf[]  = { 0x61, 0x06, 0x02, 0x03, 0x01 };
36 static uint8_t reset_ntf[] = {0x60, 0x00, 0x06, 0xA0, 0x00, 0xC7, 0xD4, 0x00, 0x00};
37 
38 static uint32_t kovio_timer;
39 
40 /************** Kovio functions ***************************************/
41 
42 static NFCSTATUS phNxpNciHal_rf_deactivate(void);
43 
44 /*******************************************************************************
45 **
46 ** Function         hal_write_cb
47 **
48 ** Description      Callback function for hal write.
49 **
50 ** Returns          None
51 **
52 *******************************************************************************/
hal_write_cb(void * pContext,phTmlNfc_TransactInfo_t * pInfo)53 static void hal_write_cb(void *pContext, phTmlNfc_TransactInfo_t *pInfo)
54 {
55     UNUSED(pContext);
56     UNUSED(pInfo);
57     return;
58 }
59 
60 /*******************************************************************************
61 **
62 ** Function         kovio_timer_handler
63 **
64 ** Description      Callback function for kovio timer.
65 **
66 ** Returns          None
67 **
68 *******************************************************************************/
kovio_timer_handler(uint32_t timerId,void * pContext)69 static void kovio_timer_handler(uint32_t timerId, void *pContext)
70 {
71     UNUSED(timerId);
72     UNUSED(pContext);
73     NXPLOG_NCIHAL_D(">> kovio_timer_handler. Did not receive RF_INTF_ACTIVATED_NTF, Kovio TAG must be removed.");
74 
75     phOsalNfc_Timer_Delete(kovio_timer);
76 
77     kovio_detected = 0x00;
78     send_to_upper_kovio=0x01;
79     disable_kovio=0x00;
80     /*
81      * send kovio deactivated ntf to upper layer.
82     */
83     NXPLOG_NCIHAL_D(">> send kovio deactivated ntf to upper layer.");
84     if (nxpncihal_ctrl.p_nfc_stack_data_cback != NULL)
85     {
86         (*nxpncihal_ctrl.p_nfc_stack_data_cback)(
87                 sizeof(rf_deactivated_ntf), rf_deactivated_ntf);
88     }
89     return;
90 }
91 
92 /*******************************************************************************
93 **
94 ** Function         phNxpNciHal_rf_deactivate
95 **
96 ** Description      Sends rf deactivate cmd to NFCC
97 **
98 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
99 **
100 *******************************************************************************/
phNxpNciHal_rf_deactivate()101 static NFCSTATUS phNxpNciHal_rf_deactivate()
102 {
103     NFCSTATUS status = NFCSTATUS_SUCCESS;
104     int cb_data;
105     int retryCnt = 0;
106 
107     do
108     {
109         retryCnt++;
110         status = phTmlNfc_Write(rf_deactivate_cmd,
111                 sizeof(rf_deactivate_cmd),
112                 (pphTmlNfc_TransactCompletionCb_t) &hal_write_cb, &cb_data);
113     } while(status != NFCSTATUS_PENDING && retryCnt <= MAX_WRITE_RETRY);
114 
115     if(status != NFCSTATUS_PENDING)
116     {
117         //phNxpNciHal_emergency_recovery();
118         if (nxpncihal_ctrl.p_nfc_stack_data_cback!= NULL &&
119             nxpncihal_ctrl.hal_open_status == TRUE)
120         {
121             NXPLOG_NCIHAL_D("Send the Core Reset NTF to upper layer, which will trigger the recovery\n");
122             //Send the Core Reset NTF to upper layer, which will trigger the 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, nxpncihal_ctrl.p_rx_data);
127         }
128     }
129 
130     return status;
131 }
132 
133 /*******************************************************************************
134 **
135 ** Function         phNxpNciHal_kovio_rsp_ext
136 **
137 ** Description      Implements kovio presence check. In BCM controller this is
138 **                  managed by NFCC. But since PN54X does not handle this, the
139 **                  presence check is mimiced here.
140 **                  For the very first time Kovio is detected, NTF has to be
141 **                  passed on to upper layer. for every NTF, DH send a deactivated
142 **                  command to NFCC and NFCC follows this up with another activated
143 **                  notification. When the tag is removed, activated notification
144 **                  stops coming and this is indicated to upper layer with a HAL
145 **                  generated deactivated notification.
146 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
147 **
148 *******************************************************************************/
phNxpNciHal_kovio_rsp_ext(uint8_t * p_ntf,uint16_t * p_len)149 NFCSTATUS phNxpNciHal_kovio_rsp_ext(uint8_t *p_ntf, uint16_t *p_len)
150 {
151     NFCSTATUS status = NFCSTATUS_SUCCESS;
152     uint8_t tBuff[KOVIO_ACT_NTF_TEMP_BUFF_LEN];
153 
154     send_to_upper_kovio = 1;
155     if((p_ntf[0]==0x61)&&(p_ntf[1]==0x05))
156     {
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             {
165                 if((*p_len-9)<KOVIO_ACT_NTF_TEMP_BUFF_LEN)
166                 {
167                     p_ntf[2]+=1;
168                     memcpy(tBuff, &p_ntf[9], *p_len-9);
169                     p_ntf[9]=p_ntf[9]+1;
170                     memcpy(&p_ntf[10], tBuff, *p_len-9);
171                     *p_len+=1;
172                 }else
173                 {
174                     NXPLOG_NCIHAL_D("Kovio Act ntf payload exceeded temp buffer size");
175                 }
176                 kovio_detected = 1;
177                 kovio_timer = phOsalNfc_Timer_Create();
178                 NXPLOG_NCIHAL_D("custom kovio timer Created - %d", kovio_timer);
179             }
180             else
181             {
182                 send_to_upper_kovio = 0;
183             }
184 
185             if (!rf_deactive_cmd)
186             {
187                 NXPLOG_NCIHAL_D ("Send RF deactivate command to NFCC");
188                 status = phNxpNciHal_rf_deactivate ();
189             }
190             else
191             {
192                 NXPLOG_NCIHAL_D ("RF deactivate command is already sent to NFCC");
193                 disable_kovio = TRUE;
194                 send_to_upper_kovio = 0;
195             }
196             status = phOsalNfc_Timer_Start(kovio_timer,
197                     KOVIO_TIMEOUT,
198                     &kovio_timer_handler,
199                     NULL);
200             if (NFCSTATUS_SUCCESS == status)
201             {
202                 NXPLOG_NCIHAL_D("kovio timer started");
203             }
204             else
205             {
206                 NXPLOG_NCIHAL_E("kovio timer not started!!!");
207                 status  = NFCSTATUS_FAILED;
208             }
209         }
210         else
211         {
212             if (kovio_detected == 1)
213             {
214                 phNxpNciHal_clean_Kovio_Ext();
215                 NXPLOG_NCIHAL_D ("Disabling Kovio detection logic as another tag type detected");
216             }
217         }
218     }
219     else if((p_ntf[0]==0x41)&&(p_ntf[1]==0x06)&&(p_ntf[2]==0x01))
220     {
221         rf_deactive_cmd = FALSE;
222         if(kovio_detected == 1)
223             send_to_upper_kovio = 0;
224         if((kovio_detected == 1)&&(disable_kovio==0x01))
225         {
226             NXPLOG_NCIHAL_D ("Disabling Kovio detection logic");
227             phNxpNciHal_clean_Kovio_Ext();
228             disable_kovio=0x00;
229         }
230     }
231     else if((p_ntf[0]==0x61)&&(p_ntf[1]==0x06)&&(p_ntf[2]==0x02)&&(p_ntf[3]==0x03)&&(p_ntf[4]==0x00))
232     {
233         if(kovio_detected == 1)
234             send_to_upper_kovio = 0;
235     }
236     else if((p_ntf[0]==0x61)&&(p_ntf[1]==0x03))
237     {
238         if(kovio_detected == 1)
239             send_to_upper_kovio = 0;
240     }
241     return status;
242 }
243 /*******************************************************************************
244 **
245 ** Function         phNxpNciHal_clean_Kovio_Ext
246 **
247 ** Description      Clean up Kovio extension state machine.
248 ** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
249 **
250 *******************************************************************************/
phNxpNciHal_clean_Kovio_Ext()251 void phNxpNciHal_clean_Kovio_Ext()
252 {
253     NXPLOG_NCIHAL_D(">> Cleaning up Kovio State machine and timer.");
254     phOsalNfc_Timer_Delete(kovio_timer);
255     kovio_detected = 0x00;
256     send_to_upper_kovio=0x01;
257     disable_kovio=0x00;
258     /*
259      * send kovio deactivated ntf to upper layer.
260     */
261     NXPLOG_NCIHAL_D(">> send kovio deactivated ntf to upper layer.");
262     if (nxpncihal_ctrl.p_nfc_stack_data_cback != NULL)
263     {
264         (*nxpncihal_ctrl.p_nfc_stack_data_cback)(
265                 sizeof(rf_deactivated_ntf), rf_deactivated_ntf);
266     }
267     return;
268 }
269