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 * \file  phLlcNfc.c
19 * \brief Common LLC for the upper layer.
20 *
21 * Project: NFC-FRI-1.1
22 *
23 * $Date: Wed Apr 28 17:07:03 2010 $
24 * $Author: ing02260 $
25 * $Revision: 1.59 $
26 * $Aliases: NFC_FRI1.1_WK1017_PREP1,NFC_FRI1.1_WK1017_R34_1,NFC_FRI1.1_WK1017_R34_2,NFC_FRI1.1_WK1023_R35_1 $
27 *
28 */
29 
30 /*************************** Includes *******************************/
31 #include <phNfcTypes.h>
32 #include <phNfcStatus.h>
33 #include <phOsalNfc.h>
34 #include <phNfcInterface.h>
35 #include <phLlcNfc_DataTypes.h>
36 #include <phLlcNfc.h>
37 #include <phLlcNfc_Frame.h>
38 #include <phLlcNfc_Interface.h>
39 #include <phLlcNfc_Timer.h>
40 
41 /*********************** End of includes ****************************/
42 
43 /***************************** Macros *******************************/
44 
45 /************************ End of macros *****************************/
46 
47 /***************************** Global variables *******************************/
48 
49 #ifdef LLC_RELEASE_FLAG
50     uint8_t             g_release_flag;
51 #endif /* #ifdef LLC_RELEASE_FLAG */
52 
53 /************************ End of global variables *****************************/
54 
55 
56 
57 /*********************** Local functions ****************************/
58 /**
59 * \ingroup grp_hal_nfc_llc
60 *
61 * \brief \b Init function
62 *
63 * \copydoc page_reg Initialise all variables of the LLC component (Asynchronous function).
64 *
65 * \param[in] pContext          LLC context provided by the upper layer. The LLC
66 *                              context will be given to the upper layer through the
67 *                              \ref phLlcNfc_Register function
68 * \param[in] pLinkInfo         Link information of the hardware
69 *
70 * \retval NFCSTATUS_PENDING            If the command is yet to be processed.
71 * \retval NFCSTATUS_INVALID_PARAMETER  At least one parameter of the function is invalid.
72 * \retval Other errors                 Errors related to the lower layers
73 *
74 */
75 static
76 NFCSTATUS
77 phLlcNfc_Init (
78                void    *pContext,
79                void    *pLinkInfo
80                );
81 
82 /**
83 * \ingroup grp_hal_nfc_llc
84 *
85 * \brief \b Send function
86 *
87 * \copydoc page_reg This asynchronous function gets the information from the upper layer and creates the
88 *              proper LLC packet to send the information it to the hardware. The number of
89 *              bytes written is obtained from the send response callback which has been
90 *              registered in \ref phLlcNfc_Register function
91 *
92 * \param[in] pContext          LLC context is provided by the upper layer. The LLC
93 *                              context earlier was given to the upper layer through the
94 *                              \ref phLlcNfc_Register function
95 * \param[in] pLinkInfo         Link information of the hardware.
96 * \param[in] pLlc_Buf          The information given by the upper layer to send it to
97 *                              the lower layer
98 * \param[in] llcBufLength      the length of pLlc_Buf, that needs to be sent to the
99 *                              lower layer is given by the upper layer
100 *
101 * \retval NFCSTATUS_PENDING                If the command is yet to be process.
102 * \retval NFCSTATUS_INVALID_PARAMETER      At least one parameter of the function is invalid.
103 * \retval Other errors                     Errors related to the lower layers
104 *
105 */
106 static
107 NFCSTATUS
108 phLlcNfc_Send (
109                void            *pContext,
110                void            *pLinkInfo,
111                uint8_t         *pLlcBuf,
112                uint16_t        llcBufLength
113                );
114 
115 /**
116 * \ingroup grp_hal_nfc_llc
117 *
118 * \brief \b Receive function
119 *
120 * \copydoc page_reg This asynchronous function gets the length and the required buffer from
121 *          the upper layer to receive the information from the the hardware. The
122 *          received data will be given through the receive response callback
123 *          which has been registered in the \b phLlcNfc_Register function
124 *
125 * \param[in] pContext          LLC context is provided by the upper layer. The LLC
126 *                              context earlier was given to the upper layer through the
127 *                              \b phLlcNfc_Register function
128 * \param[in] pLinkInfo         Link information of the hardware
129 * \param[in] pLlc_Buf          The information given by the upper layer to receive data from
130 *                              the lower layer
131 * \param[in] llcBufLength      The length of pLlc_Buf given by the upper layer
132 *
133 * \retval NFCSTATUS_PENDING                If the command is yet to be process.
134 * \retval NFCSTATUS_INVALID_PARAMETER      At least one parameter of the function is invalid.
135 * \retval Other errors                     Errors related to the lower layers
136 *
137 */
138 static
139 NFCSTATUS
140 phLlcNfc_Receive (
141                   void              *pContext,
142                   void              *pLinkInfo,
143                   uint8_t           *pLlcBuf,
144                   uint16_t          llcBufLength
145                   );
146 /******************** End of Local functions ************************/
147 
148 /********************** Global variables ****************************/
149 
150 /******************** End of Global Variables ***********************/
151 
152 NFCSTATUS
phLlcNfc_Register(phNfcIF_sReference_t * psReference,phNfcIF_sCallBack_t if_callback,void * psIFConfig)153 phLlcNfc_Register (
154     phNfcIF_sReference_t        *psReference,
155     phNfcIF_sCallBack_t         if_callback,
156     void                        *psIFConfig
157 )
158 {
159     NFCSTATUS               result = NFCSTATUS_SUCCESS;
160     phLlcNfc_Context_t      *ps_llc_ctxt = NULL;
161     phNfcLayer_sCfg_t       *psconfig = (phNfcLayer_sCfg_t *)psIFConfig;
162 
163     PH_LLCNFC_PRINT("Llc Register called\n");
164     if ((NULL == psReference) || (NULL == psIFConfig) ||
165         (NULL == psReference->plower_if) ||
166 #if 0
167         (NULL == if_callback.pif_ctxt) ||
168 #endif
169         (NULL == if_callback.notify) ||
170         (NULL == if_callback.receive_complete) ||
171         (NULL == if_callback.send_complete))
172     {
173         result = PHNFCSTVAL(CID_NFC_LLC,
174                             NFCSTATUS_INVALID_PARAMETER);
175     }
176     else
177     {
178         /* Now LLC is in RESET state */
179         ps_llc_ctxt = (phLlcNfc_Context_t*)phOsalNfc_GetMemory(
180                                         sizeof(phLlcNfc_Context_t));
181         if (NULL == ps_llc_ctxt)
182         {
183             /* Memory allocation failed */
184             result = PHNFCSTVAL(CID_NFC_LLC,
185                                 NFCSTATUS_INSUFFICIENT_RESOURCES);
186         }
187         else
188         {
189             result = NFCSTATUS_SUCCESS;
190 
191             (void)memset(ps_llc_ctxt, 0, sizeof(phLlcNfc_Context_t));
192 
193             /* Register the LLC functions to the upper layer */
194             psReference->plower_if->init = (pphNfcIF_Interface_t)&phLlcNfc_Init;
195             psReference->plower_if->release = (pphNfcIF_Interface_t)&phLlcNfc_Release;
196             psReference->plower_if->send = (pphNfcIF_Transact_t)&phLlcNfc_Send;
197             psReference->plower_if->receive = (pphNfcIF_Transact_t)&phLlcNfc_Receive;
198             /* Copy the LLC context to the upper layer */
199             psReference->plower_if->pcontext = ps_llc_ctxt;
200 
201             /* Register the callback function from the upper layer */
202             ps_llc_ctxt->cb_for_if.receive_complete = if_callback.receive_complete;
203             ps_llc_ctxt->cb_for_if.send_complete = if_callback.send_complete;
204             ps_llc_ctxt->cb_for_if.notify = if_callback.notify;
205             /* Get the upper layer context */
206             ps_llc_ctxt->cb_for_if.pif_ctxt = if_callback.pif_ctxt;
207 
208             result = phLlcNfc_Interface_Register(ps_llc_ctxt, psconfig);
209 
210             if (NFCSTATUS_SUCCESS == result)
211             {
212 #ifdef LLC_RELEASE_FLAG
213                 g_release_flag = FALSE;
214 #endif /* #ifdef LLC_RELEASE_FLAG */
215             }
216         }
217     }
218     PH_LLCNFC_DEBUG("Llc Register result : 0x%x\n", result);
219     return result;
220 }
221 
222 static
223 NFCSTATUS
phLlcNfc_Init(void * pContext,void * pLinkInfo)224 phLlcNfc_Init (
225     void    *pContext,
226     void    *pLinkInfo
227 )
228 {
229     NFCSTATUS               result = NFCSTATUS_SUCCESS;
230     phLlcNfc_Context_t      *ps_llc_ctxt = (phLlcNfc_Context_t*)pContext;
231     phLlcNfc_LlcPacket_t    s_packet_info;
232 
233     PH_LLCNFC_PRINT("Llc Init called\n");
234     if ((NULL == ps_llc_ctxt) || (NULL == pLinkInfo))
235     {
236         result = PHNFCSTVAL(CID_NFC_LLC,
237                             NFCSTATUS_INVALID_PARAMETER);
238     }
239     else
240     {
241         /* Initialisation */
242         ps_llc_ctxt->phwinfo = pLinkInfo;
243         /* Call the internal frame initialise */
244         phLlcNfc_H_Frame_Init(ps_llc_ctxt);
245         /* Call the internal LLC TL interface initialise */
246         result = phLlcNfc_Interface_Init(ps_llc_ctxt);
247         if (NFCSTATUS_SUCCESS == result)
248         {
249             /* Call the internal LLC timer initialise */
250             result = phLlcNfc_TimerInit(ps_llc_ctxt);
251         }
252 
253         if (NFCSTATUS_SUCCESS == result)
254         {
255             /* Create the static timer */
256             phLlcNfc_CreateTimers();
257 
258             /* Create a U frame */
259             result = phLlcNfc_H_CreateUFramePayload(ps_llc_ctxt,
260                                     &s_packet_info,
261                                     &(s_packet_info.llcbuf_len),
262                                     phLlcNfc_e_rset);
263         }
264         if (NFCSTATUS_SUCCESS == result)
265         {
266             /* Call DAL write */
267             result = phLlcNfc_Interface_Write(ps_llc_ctxt,
268                                 (uint8_t*)&(s_packet_info.s_llcbuf),
269                                 (uint32_t)s_packet_info.llcbuf_len);
270         }
271         if (NFCSTATUS_PENDING == result)
272         {
273             /* Start the timer */
274             result = phLlcNfc_StartTimers(PH_LLCNFC_CONNECTIONTIMER, 0);
275             if (NFCSTATUS_SUCCESS == result)
276             {
277                 ps_llc_ctxt->s_frameinfo.sent_frame_type =
278                                                         init_u_rset_frame;
279                 result = NFCSTATUS_PENDING;
280             }
281         }
282 
283         if (NFCSTATUS_PENDING != result)
284         {
285             (void)phLlcNfc_Release(ps_llc_ctxt, pLinkInfo);
286         }
287     }
288     PH_LLCNFC_DEBUG("Llc Init result : 0x%x\n", result);
289     return result;
290 }
291 
292 NFCSTATUS
phLlcNfc_Release(void * pContext,void * pLinkInfo)293 phLlcNfc_Release(
294     void    *pContext,
295     void    *pLinkInfo
296 )
297 {
298     NFCSTATUS               result = PHNFCSTVAL(CID_NFC_LLC,
299                                             NFCSTATUS_INVALID_PARAMETER);
300     phLlcNfc_Context_t     *ps_llc_ctxt = (phLlcNfc_Context_t*)pContext;
301     /*
302         1. Free all the memory allocated in initialise
303     */
304     PH_LLCNFC_PRINT("Llc release called\n");
305 
306     if ((NULL != ps_llc_ctxt) && (NULL != pLinkInfo))
307     {
308         result = NFCSTATUS_SUCCESS;
309         ps_llc_ctxt->phwinfo = pLinkInfo;
310 #ifdef INCLUDE_DALINIT_DEINIT
311         if (NULL != ps_llc_ctxt->lower_if.release)
312         {
313             result = ps_llc_ctxt->lower_if.release(
314                             ps_llc_ctxt->lower_if.pcontext,
315                             pLinkInfo);
316         }
317 #endif
318         if (NULL != ps_llc_ctxt->lower_if.transact_abort)
319         {
320             result = ps_llc_ctxt->lower_if.transact_abort(
321                             ps_llc_ctxt->lower_if.pcontext,
322                             pLinkInfo);
323         }
324         if (NULL != ps_llc_ctxt->lower_if.unregister)
325         {
326             result = ps_llc_ctxt->lower_if.unregister(
327                             ps_llc_ctxt->lower_if.pcontext,
328                             pLinkInfo);
329         }
330 
331         /* Call the internal LLC timer un-initialise */
332         phLlcNfc_TimerUnInit(ps_llc_ctxt);
333         phLlcNfc_H_Frame_DeInit(&ps_llc_ctxt->s_frameinfo);
334         (void)memset(ps_llc_ctxt, 0, sizeof(phLlcNfc_Context_t));
335         phOsalNfc_FreeMemory(ps_llc_ctxt);
336         ps_llc_ctxt = NULL;
337 
338 #ifdef LLC_RELEASE_FLAG
339         g_release_flag = TRUE;
340 #endif /* #ifdef LLC_RELEASE_FLAG */
341 
342     }
343     PH_LLCNFC_DEBUG("Llc release result : 0x%04X\n", result);
344     return result;
345 }
346 
347 static
348 NFCSTATUS
phLlcNfc_Send(void * pContext,void * pLinkInfo,uint8_t * pLlcBuf,uint16_t llcBufLength)349 phLlcNfc_Send (
350     void            *pContext,
351     void            *pLinkInfo,
352     uint8_t         *pLlcBuf,
353     uint16_t        llcBufLength
354 )
355 {
356     /*
357         1. Check the function parameters for valid values
358         2. Create the I frame llc payload using the upper layer buffer
359         3. Send the updated buffer to the below layer
360         4. Store the I frame in a list, till acknowledge is received
361     */
362     NFCSTATUS               result = NFCSTATUS_SUCCESS;
363     phLlcNfc_Context_t      *ps_llc_ctxt = (phLlcNfc_Context_t*)pContext;
364     phLlcNfc_Frame_t        *ps_frame_info = NULL;
365     phLlcNfc_LlcPacket_t    s_packet_info;
366     phLlcNfc_StoreIFrame_t  *ps_store_frame = NULL;
367 #if 0
368     uint8_t                 count = 1;
369 #endif /* #if 0 */
370 
371     PH_LLCNFC_PRINT ("Llc Send called\n");
372     if ((NULL == ps_llc_ctxt) || (NULL == pLinkInfo) ||
373         (NULL == pLlcBuf) || (0 == llcBufLength) ||
374         (llcBufLength > PH_LLCNFC_MAX_IFRAME_BUFLEN))
375     {
376         /* Parameter check failed */
377         result = PHNFCSTVAL(CID_NFC_LLC,
378                             NFCSTATUS_INVALID_PARAMETER);
379     }
380     else if (ps_llc_ctxt->s_frameinfo.s_send_store.winsize_cnt >=
381             ps_llc_ctxt->s_frameinfo.window_size)
382     {
383         /* Window size check failed */
384         result = PHNFCSTVAL(CID_NFC_LLC,
385                             NFCSTATUS_NOT_ALLOWED);
386     }
387     else
388     {
389         ps_frame_info = &(ps_llc_ctxt->s_frameinfo);
390         ps_store_frame = &(ps_frame_info->s_send_store);
391 
392         PH_LLCNFC_DEBUG ("Buffer length : 0x%04X\n", llcBufLength);
393         PH_LLCNFC_PRINT_BUFFER (pLlcBuf, llcBufLength);
394 
395         /* Copy the hardware information */
396         ps_llc_ctxt->phwinfo = pLinkInfo;
397 
398         /* Create I frame with the user buffer  */
399         (void)phLlcNfc_H_CreateIFramePayload (
400                                 &(ps_llc_ctxt->s_frameinfo),
401                                 &s_packet_info,
402                                 pLlcBuf, (uint8_t)llcBufLength);
403 
404 
405         /* Store the I frame in the send list */
406         (void)phLlcNfc_H_StoreIFrame (ps_store_frame, s_packet_info);
407         result = NFCSTATUS_PENDING;
408 
409 #ifdef CTRL_WIN_SIZE_COUNT
410 
411         /* No check required */
412         if ((TRUE != ps_frame_info->write_pending) &&
413             (PH_LLCNFC_READPEND_REMAIN_BYTE !=
414             ps_frame_info->read_pending))
415 
416 #else /* #ifdef CTRL_WIN_SIZE_COUNT */
417 
418         if (1 == ps_frame_info->s_send_store.winsize_cnt)
419 
420 #endif /* #ifdef CTRL_WIN_SIZE_COUNT */
421         {
422             /* Call write to the below layer, only if previous write
423                 is completed */
424             result = phLlcNfc_Interface_Write (ps_llc_ctxt,
425                                 (uint8_t *)&(s_packet_info.s_llcbuf),
426                                 (uint32_t)s_packet_info.llcbuf_len);
427 
428             if ((NFCSTATUS_PENDING == result) ||
429                 (NFCSTATUS_BUSY == PHNFCSTATUS (result)))
430             {
431                 ps_frame_info->write_status = result;
432                 if (NFCSTATUS_BUSY == PHNFCSTATUS(result))
433                 {
434                     result = NFCSTATUS_PENDING;
435                     ps_frame_info->write_wait_call = (phLlcNfc_eSentFrameType_t)
436                             ((resend_i_frame == ps_frame_info->write_wait_call) ?
437                             ps_frame_info->write_wait_call : user_i_frame);
438                 }
439                 else
440                 {
441                     /* Start the timer */
442                     (void)phLlcNfc_StartTimers (PH_LLCNFC_GUARDTIMER,
443                                                 ps_frame_info->n_s);
444 
445                     /* "sent_frame_type is updated" only if the data is
446                         written to the lower layer */
447                     ps_frame_info->sent_frame_type = user_i_frame;
448                 }
449             }
450 #if 0
451             /* Get the added frame array count */
452             count = (uint8_t)((((ps_store_frame->start_pos +
453                             ps_store_frame->winsize_cnt) - count)) %
454                             PH_LLCNFC_MOD_NS_NR);
455 #endif /* #if 0 */
456         }
457         else
458         {
459             ps_frame_info->write_status = PHNFCSTVAL(CID_NFC_LLC, NFCSTATUS_BUSY);
460             ps_frame_info->write_wait_call = (phLlcNfc_eSentFrameType_t)
461                             ((resend_i_frame == ps_frame_info->write_wait_call) ?
462                             ps_frame_info->write_wait_call : user_i_frame);
463         }
464     }
465 
466 
467     PH_LLCNFC_DEBUG ("Llc Send result : 0x%04X\n", result);
468     return result;
469 }
470 
471 static
472 NFCSTATUS
phLlcNfc_Receive(void * pContext,void * pLinkInfo,uint8_t * pLlcBuf,uint16_t llcBufLength)473 phLlcNfc_Receive (
474     void            *pContext,
475     void            *pLinkInfo,
476     uint8_t         *pLlcBuf,
477     uint16_t        llcBufLength
478 )
479 {
480     NFCSTATUS               result = NFCSTATUS_SUCCESS;
481     phLlcNfc_Context_t      *ps_llc_ctxt = (phLlcNfc_Context_t*)pContext;
482     phLlcNfc_LlcPacket_t    *ps_recv_pkt = NULL;
483 
484     PH_LLCNFC_PRINT("Llc Receive called\n");
485     if ((NULL == ps_llc_ctxt) || (NULL == pLinkInfo) ||
486         (NULL == pLlcBuf) || (0 == llcBufLength) ||
487         (llcBufLength > PH_LLCNFC_MAX_IFRAME_BUFLEN))
488     {
489         result = PHNFCSTVAL(CID_NFC_LLC,
490                             NFCSTATUS_INVALID_PARAMETER);
491     }
492     else
493     {
494         ps_llc_ctxt->phwinfo = pLinkInfo;
495 
496         ps_recv_pkt = &(ps_llc_ctxt->s_frameinfo.s_recvpacket);
497         /* Always read the first byte to read the length, then
498         read the entire data later using the 1 byte buffer */
499         llcBufLength = PH_LLCNFC_BYTES_INIT_READ;
500         /* Call write to the below layer */
501         result = phLlcNfc_Interface_Read(ps_llc_ctxt,
502                                 PH_LLCNFC_READWAIT_OFF,
503                                 &(ps_recv_pkt->s_llcbuf.llc_length_byte),
504                                 llcBufLength);
505 
506         ps_llc_ctxt->s_frameinfo.upper_recv_call = TRUE;
507         if (NFCSTATUS_PENDING != result)
508         {
509             ps_llc_ctxt->state = phLlcNfc_Initialised_State;
510         }
511     }
512     PH_LLCNFC_DEBUG("Llc Receive result : 0x%04X\n", result);
513     return result;
514 }
515