1 /*
2  * Copyright (C) 2010 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 
18 /*!
19 * =========================================================================== *
20 *                                                                             *
21 *                                                                             *
22 * \file  phHciNfc_LinkMgmt.c                                                  *
23 * \brief HCI Link Management Gate Routines.                                   *
24 *                                                                             *
25 *                                                                             *
26 * Project: NFC-FRI-1.1                                                        *
27 *                                                                             *
28 * $Date: Thu Feb 11 18:52:19 2010 $                                           *
29 * $Author: ing04880 $                                                         *
30 * $Revision: 1.11 $                                                            *
31 * $Aliases: NFC_FRI1.1_WK1007_R33_1,NFC_FRI1.1_WK1007_R33_4,NFC_FRI1.1_WK1017_PREP1,NFC_FRI1.1_WK1017_R34_1,NFC_FRI1.1_WK1017_R34_2,NFC_FRI1.1_WK1023_R35_1 $                                                                *
32 *                                                                             *
33 * =========================================================================== *
34 */
35 
36 /*
37 ***************************** Header File Inclusion ****************************
38 */
39 #include <phNfcCompId.h>
40 #include <phHciNfc_Pipe.h>
41 #include <phHciNfc_LinkMgmt.h>
42 #include <phOsalNfc.h>
43 
44 /*
45 ****************************** Macro Definitions *******************************
46 */
47 
48 #define REC_ERROR_INDEX         0x01U
49 
50 #define REC_RETRY_LEN           0x02U
51 
52 /*
53 *************************** Structure and Enumeration ***************************
54 */
55 
56 
57 /** \defgroup grp_hci_nfc HCI Link Management Component
58  *
59  *
60  */
61 
62 typedef enum phHciNfc_LinkMgmt_Seq{
63     LINK_MGMT_PIPE_OPEN     = 0x00U,
64     LINK_MGMT_GET_REC_ERROR,
65     LINK_MGMT_SET_REC_ERROR,
66     LINK_MGMT_PIPE_CLOSE
67 } phHciNfc_LinkMgmt_Seq_t;
68 
69 typedef struct phHciNfc_LinkMgmt_Info{
70     phHciNfc_LinkMgmt_Seq_t link_cur_seq;
71     phHciNfc_LinkMgmt_Seq_t link_next_seq;
72     phHciNfc_Pipe_Info_t    *p_pipe_info;
73     /* Rec Error Count Number from the Host Controller */
74     uint16_t                hc_rec_error;
75     /* Rec Error Count Number of the Terminal Host */
76     uint16_t                rec_error;
77 } phHciNfc_LinkMgmt_Info_t;
78 
79 
80 /*
81 *************************** Static Function Declaration **************************
82 */
83 
84 static
85 NFCSTATUS
86 phHciNfc_LinkMgmt_InfoUpdate(
87                                 phHciNfc_sContext_t     *psHciContext,
88                                 phHal_sHwReference_t    *pHwRef,
89                                 uint8_t                 index,
90                                 uint8_t                 *reg_value,
91                                 uint8_t                 reg_length
92                          );
93 static
94 NFCSTATUS
95 phHciNfc_Recv_LinkMgmt_Response(
96                         void                *psHciContext,
97                         void                *pHwRef,
98                         uint8_t             *pResponse,
99 #ifdef ONE_BYTE_LEN
100                         uint8_t             length
101 #else
102                         uint16_t            length
103 #endif
104                        );
105 
106 
107 /*
108 *************************** Function Definitions ***************************
109 */
110 
111 
112 
113 
114 /*!
115  * \brief Initialisation of Link Managment Gate.
116  *
117  * This function initialses the Link Management gate and
118  * populates the Link Management Information Structure
119  *
120  */
121 
122 NFCSTATUS
phHciNfc_LinkMgmt_Initialise(phHciNfc_sContext_t * psHciContext,void * pHwRef)123 phHciNfc_LinkMgmt_Initialise(
124                                 phHciNfc_sContext_t     *psHciContext,
125                                 void                    *pHwRef
126                          )
127 {
128     NFCSTATUS                           status = NFCSTATUS_SUCCESS;
129     phHciNfc_Pipe_Info_t                *p_pipe_info = NULL;
130     phHciNfc_LinkMgmt_Info_t            *p_link_mgmt_info=NULL;
131     uint8_t                             link_pipe_id = (uint8_t)HCI_UNKNOWN_PIPE_ID;
132 
133     if( ( NULL == psHciContext )
134         || (NULL == pHwRef )
135         )
136     {
137         status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
138     }
139     else
140     {
141         if( ( NULL == psHciContext->p_link_mgmt_info )
142             && (phHciNfc_Allocate_Resource((void **)(&p_link_mgmt_info),
143                     sizeof(phHciNfc_LinkMgmt_Info_t))== NFCSTATUS_SUCCESS)
144           )
145         {
146             psHciContext->p_link_mgmt_info = p_link_mgmt_info;
147             p_link_mgmt_info->link_cur_seq = LINK_MGMT_PIPE_OPEN;
148             p_link_mgmt_info->link_next_seq = LINK_MGMT_PIPE_OPEN;
149             p_link_mgmt_info->p_pipe_info = NULL;
150         }
151         else
152         {
153             p_link_mgmt_info = (phHciNfc_LinkMgmt_Info_t *)
154                                 psHciContext->p_link_mgmt_info ;
155         }
156 
157         if( NULL == p_link_mgmt_info )
158         {
159             status = PHNFCSTVAL(CID_NFC_HCI,
160                         NFCSTATUS_INVALID_HCI_INFORMATION);
161         }
162 #ifdef ESTABLISH_SESSION
163         else if( hciMode_Session == psHciContext->hci_mode )
164         {
165             status = NFCSTATUS_SUCCESS;
166         }
167 #endif
168         else
169         {
170             switch(p_link_mgmt_info->link_cur_seq )
171             {
172                 /* Link Mgmt pipe open sequence */
173                 case LINK_MGMT_PIPE_OPEN:
174                 {
175                     if(phHciNfc_Allocate_Resource((void **)(&p_pipe_info),
176                         sizeof(phHciNfc_Pipe_Info_t))!= NFCSTATUS_SUCCESS)
177                     {
178                         status = PHNFCSTVAL(CID_NFC_HCI,
179                                 NFCSTATUS_INSUFFICIENT_RESOURCES);
180                     }
181                     else
182                     {
183                         /* Populate the pipe information in the pipe handle */
184                         ((phHciNfc_Pipe_Info_t *)p_pipe_info)->pipe.pipe_id =
185                                         PIPETYPE_STATIC_LINK;
186                         ((phHciNfc_Pipe_Info_t *)p_pipe_info)->recv_resp =
187                                         &phHciNfc_Recv_LinkMgmt_Response;
188                         psHciContext->p_pipe_list[PIPETYPE_STATIC_LINK] =
189                                                                     p_pipe_info ;
190                         status = phHciNfc_Open_Pipe( psHciContext,
191                                                             pHwRef,p_pipe_info );
192                         if(status == NFCSTATUS_SUCCESS)
193                         {
194                             p_link_mgmt_info->p_pipe_info = p_pipe_info ;
195                             p_link_mgmt_info->link_next_seq =
196                                                     LINK_MGMT_GET_REC_ERROR;
197                             status = NFCSTATUS_PENDING;
198                         }
199                     }
200                     break;
201                 }
202                 case LINK_MGMT_GET_REC_ERROR:
203                 {
204                     p_pipe_info = p_link_mgmt_info->p_pipe_info;
205                     if(NULL == p_pipe_info )
206                     {
207                         status = PHNFCSTVAL(CID_NFC_HCI,
208                                         NFCSTATUS_INVALID_HCI_SEQUENCE);
209                     }
210                     else
211                     {
212                         p_pipe_info->reg_index = REC_ERROR_INDEX;
213                         link_pipe_id = PIPETYPE_STATIC_LINK ;
214                         status =
215                             phHciNfc_Send_Generic_Cmd( psHciContext, pHwRef,
216                                 link_pipe_id,   (uint8_t)ANY_GET_PARAMETER );
217                         if(NFCSTATUS_PENDING == status )
218                         {
219                             p_link_mgmt_info->link_next_seq =
220                                                         LINK_MGMT_PIPE_CLOSE;
221                             status = NFCSTATUS_SUCCESS;
222                         }
223                     }
224                     break;
225                 }
226                 case LINK_MGMT_SET_REC_ERROR:
227                 {
228                     p_pipe_info = p_link_mgmt_info->p_pipe_info;
229                     if(NULL == p_pipe_info )
230                     {
231                         status = PHNFCSTVAL(CID_NFC_HCI,
232                                         NFCSTATUS_INVALID_HCI_SEQUENCE);
233                     }
234                     else
235                     {
236                         p_pipe_info->reg_index = REC_ERROR_INDEX;
237                         link_pipe_id = PIPETYPE_STATIC_LINK ;
238                         status =
239                             phHciNfc_Send_Generic_Cmd( psHciContext, pHwRef,
240                                 link_pipe_id,   (uint8_t)ANY_GET_PARAMETER );
241                         if(NFCSTATUS_PENDING == status )
242                         {
243                             p_link_mgmt_info->link_next_seq =
244                                                         LINK_MGMT_PIPE_CLOSE;
245                             status = NFCSTATUS_SUCCESS;
246                         }
247                     }
248                     break;
249                 }
250                 default:
251                 {
252                     status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_SEQUENCE);
253                     break;
254                 }
255 
256             }/* End of the Sequence Switch */
257 
258         }/* End of the Link Info Memory Check */
259     } /* End of Null Context Check */
260 
261     return status;
262 }
263 
264 /*!
265  * \brief Opens the Link Management Pipe of the Link Management Gate.
266  *
267  * This function Opens the Link Management Pipe of the Link Management
268  * Gate and Confirms that the HCI Link is behaving as expected.
269  */
270 
271 NFCSTATUS
phHciNfc_LinkMgmt_Open(phHciNfc_sContext_t * psHciContext,void * pHwRef)272 phHciNfc_LinkMgmt_Open(
273                                 phHciNfc_sContext_t     *psHciContext,
274                                 void                    *pHwRef
275                              )
276 {
277     NFCSTATUS                           status = NFCSTATUS_SUCCESS;
278 
279     if( (NULL == psHciContext) || (NULL == pHwRef) )
280     {
281       status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
282     }
283     else
284     {
285         phHciNfc_LinkMgmt_Info_t  *p_link_mgmt_info=
286             (phHciNfc_LinkMgmt_Info_t *)psHciContext->p_link_mgmt_info ;
287         if(( NULL != p_link_mgmt_info ) &&
288                 ( NULL != p_link_mgmt_info->p_pipe_info  ))
289         {
290             status = phHciNfc_Open_Pipe( psHciContext,
291                             pHwRef, p_link_mgmt_info->p_pipe_info );
292             if(status == NFCSTATUS_SUCCESS)
293             {
294                 status = NFCSTATUS_PENDING;
295             }
296         }
297         else
298         {
299             status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_NOT_ALLOWED);
300 
301         }/* End of the Identity Info Memory Check */
302 
303     } /* End of Null Context Check */
304 
305     return status;
306 }
307 
308 
309 NFCSTATUS
phHciNfc_LinkMgmt_Release(phHciNfc_sContext_t * psHciContext,void * pHwRef)310 phHciNfc_LinkMgmt_Release(
311                                 phHciNfc_sContext_t     *psHciContext,
312                                 void                    *pHwRef
313                              )
314 {
315     NFCSTATUS                           status = NFCSTATUS_SUCCESS;
316     phHciNfc_LinkMgmt_Info_t            *p_link_mgmt_info=NULL;
317 
318     if( (NULL == psHciContext) || (NULL == pHwRef) )
319     {
320       status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
321     }
322     else
323     {
324         if( NULL != psHciContext->p_link_mgmt_info )
325         {
326             p_link_mgmt_info = (phHciNfc_LinkMgmt_Info_t *)
327                                 psHciContext->p_link_mgmt_info ;
328             status = phHciNfc_Close_Pipe( psHciContext,
329                             pHwRef, p_link_mgmt_info->p_pipe_info );
330         }
331         else
332         {
333             status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_NOT_ALLOWED);
334 
335         }/* End of the Identity Info Memory Check */
336 
337 
338     } /* End of Null Context Check */
339 
340     return status;
341 }
342 
343 
344 /*!
345  * \brief Receives the HCI Response from the corresponding peripheral device.
346  *
347  * This function receives the HCI Command Response from the connected NFC
348  * Pheripheral device.
349  */
350 static
351 NFCSTATUS
phHciNfc_Recv_LinkMgmt_Response(void * psContext,void * pHwRef,uint8_t * pResponse,uint8_t length)352 phHciNfc_Recv_LinkMgmt_Response(
353                         void                *psContext,
354                         void                *pHwRef,
355                         uint8_t             *pResponse,
356 #ifdef ONE_BYTE_LEN
357                         uint8_t             length
358 #else
359                         uint16_t            length
360 #endif
361                     )
362 {
363     phHciNfc_sContext_t         *psHciContext =
364                                     (phHciNfc_sContext_t *)psContext ;
365     phHciNfc_LinkMgmt_Info_t    *p_link_mgmt_info=NULL;
366     NFCSTATUS                   status = NFCSTATUS_SUCCESS;
367     uint8_t                     prev_cmd = ANY_GET_PARAMETER;
368 
369     if( (NULL == psHciContext) || (NULL == pHwRef) )
370     {
371       status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
372     }
373     else if(  NULL == psHciContext->p_link_mgmt_info )
374     {
375         status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED);
376     }
377     else
378     {
379         p_link_mgmt_info = (phHciNfc_LinkMgmt_Info_t *)
380                             psHciContext->p_link_mgmt_info ;
381         prev_cmd = p_link_mgmt_info->p_pipe_info->prev_msg ;
382         switch(prev_cmd)
383         {
384             case ANY_GET_PARAMETER:
385             {
386                 status = phHciNfc_LinkMgmt_InfoUpdate(psHciContext,
387                             (phHal_sHwReference_t *)pHwRef,
388                             p_link_mgmt_info->p_pipe_info->reg_index,
389                             &pResponse[HCP_HEADER_LEN],
390                                 (uint8_t)(length - HCP_HEADER_LEN));
391                 break;
392             }
393             case ANY_SET_PARAMETER:
394             {
395                 status = PHNFCSTVAL(CID_NFC_HCI,
396                                     NFCSTATUS_FEATURE_NOT_SUPPORTED);
397                 break;
398             }
399             case ANY_OPEN_PIPE:
400             {
401                 break;
402             }
403             case ANY_CLOSE_PIPE:
404             {
405                 phOsalNfc_FreeMemory(p_link_mgmt_info->p_pipe_info);
406                 p_link_mgmt_info->p_pipe_info = NULL;
407                 psHciContext->p_pipe_list[PIPETYPE_STATIC_LINK] = NULL;
408                 break;
409             }
410             default:
411             {
412                 status = PHNFCSTVAL(CID_NFC_HCI,
413                                         NFCSTATUS_INVALID_HCI_RESPONSE);
414                 break;
415             }
416         }
417         if( NFCSTATUS_SUCCESS == status )
418         {
419             if( NULL != p_link_mgmt_info->p_pipe_info)
420             {
421                 p_link_mgmt_info->p_pipe_info->prev_status = NFCSTATUS_SUCCESS;
422             }
423             p_link_mgmt_info->link_cur_seq = p_link_mgmt_info->link_next_seq;
424         }
425 
426     }
427     return status;
428 }
429 
430 
431 static
432 NFCSTATUS
phHciNfc_LinkMgmt_InfoUpdate(phHciNfc_sContext_t * psHciContext,phHal_sHwReference_t * pHwRef,uint8_t index,uint8_t * reg_value,uint8_t reg_length)433 phHciNfc_LinkMgmt_InfoUpdate(
434                                 phHciNfc_sContext_t     *psHciContext,
435                                 phHal_sHwReference_t    *pHwRef,
436                                 uint8_t                 index,
437                                 uint8_t                 *reg_value,
438                                 uint8_t                 reg_length
439                           )
440 {
441     phHciNfc_LinkMgmt_Info_t    *p_link_mgmt_info=NULL;
442     NFCSTATUS                   status = NFCSTATUS_SUCCESS;
443     uint8_t                     i=0;
444     if( (NULL == psHciContext)
445         || (NULL == pHwRef)
446         || (NULL == reg_value)
447         || (reg_length == 0)
448       )
449     {
450         status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER);
451     }
452     else if ( NULL == psHciContext->p_link_mgmt_info )
453     {
454         status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_INFORMATION);
455     }
456     else
457     {
458         p_link_mgmt_info = (phHciNfc_LinkMgmt_Info_t *)
459                                 psHciContext->p_link_mgmt_info ;
460         if (REC_ERROR_INDEX == index)
461         {
462             HCI_PRINT_BUFFER("\tHost Controller REC Error Count :",reg_value,reg_length);
463             /* p_link_mgmt_info->hc_rec_error = reg_value[i] ; */
464             for(i=0 ;(reg_length == REC_RETRY_LEN)&&(i < reg_length); i++)
465             {
466                 p_link_mgmt_info->hc_rec_error |=
467                             (uint16_t)(reg_value[i] << (BYTE_SIZE * i));
468             }
469         }
470         else
471         {
472             status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_INFORMATION);
473         } /* End of the Index Check */
474 
475     } /* End of Context and the Link information validity check */
476 
477     return status;
478 }
479