1/*
2 * Copyright (C) 2010-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/*
18 * DAL I2C port implementation for linux
19 *
20 * Project: Trusted NFC Linux
21 *
22 */
23#include <hardware/nfc.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <termios.h>
28#include <sys/ioctl.h>
29#include <sys/select.h>
30#include <errno.h>
31
32#include <phNxpLog.h>
33#include <phTmlNfc_i2c.h>
34#include <phNfcStatus.h>
35#include <string.h>
36#include "phNxpNciHal_utils.h"
37
38#define CRC_LEN                     2
39#define NORMAL_MODE_HEADER_LEN      3
40#define FW_DNLD_HEADER_LEN          2
41#define FW_DNLD_LEN_OFFSET          1
42#define NORMAL_MODE_LEN_OFFSET      2
43#define FRAGMENTSIZE_MAX            PHNFC_I2C_FRAGMENT_SIZE
44static bool_t bFwDnldFlag = FALSE;
45
46/*******************************************************************************
47**
48** Function         phTmlNfc_i2c_close
49**
50** Description      Closes PN54X device
51**
52** Parameters       pDevHandle - device handle
53**
54** Returns          None
55**
56*******************************************************************************/
57void phTmlNfc_i2c_close(void *pDevHandle)
58{
59    if (NULL != pDevHandle)
60    {
61        close((intptr_t)pDevHandle);
62    }
63
64    return;
65}
66
67/*******************************************************************************
68**
69** Function         phTmlNfc_i2c_open_and_configure
70**
71** Description      Open and configure PN54X device
72**
73** Parameters       pConfig     - hardware information
74**                  pLinkHandle - device handle
75**
76** Returns          NFC status:
77**                  NFCSTATUS_SUCCESS            - open_and_configure operation success
78**                  NFCSTATUS_INVALID_DEVICE     - device open operation failure
79**
80*******************************************************************************/
81NFCSTATUS phTmlNfc_i2c_open_and_configure(pphTmlNfc_Config_t pConfig, void ** pLinkHandle)
82{
83    int nHandle;
84
85
86    NXPLOG_TML_D("Opening port=%s\n", pConfig->pDevName);
87    /* open port */
88    nHandle = open((char const *)pConfig->pDevName, O_RDWR);
89    if (nHandle < 0)
90    {
91        NXPLOG_TML_E("_i2c_open() Failed: retval %x",nHandle);
92        *pLinkHandle = NULL;
93        return NFCSTATUS_INVALID_DEVICE;
94    }
95
96    *pLinkHandle = (void*) ((intptr_t)nHandle);
97
98    /*Reset PN54X*/
99    phTmlNfc_i2c_reset((void *)((intptr_t)nHandle), 1);
100    usleep(100 * 1000);
101    phTmlNfc_i2c_reset((void *)((intptr_t)nHandle), 0);
102    usleep(100 * 1000);
103    phTmlNfc_i2c_reset((void *)((intptr_t)nHandle), 1);
104
105    return NFCSTATUS_SUCCESS;
106}
107
108/*******************************************************************************
109**
110** Function         phTmlNfc_i2c_read
111**
112** Description      Reads requested number of bytes from PN54X device into given buffer
113**
114** Parameters       pDevHandle       - valid device handle
115**                  pBuffer          - buffer for read data
116**                  nNbBytesToRead   - number of bytes requested to be read
117**
118** Returns          numRead   - number of successfully read bytes
119**                  -1        - read operation failure
120**
121*******************************************************************************/
122int phTmlNfc_i2c_read(void *pDevHandle, uint8_t * pBuffer, int nNbBytesToRead)
123{
124    int ret_Read;
125    int ret_Select;
126    int numRead = 0;
127    struct timeval tv;
128    fd_set rfds;
129    uint16_t totalBtyesToRead = 0;
130
131    int i;
132    UNUSED(nNbBytesToRead);
133    if (NULL == pDevHandle)
134    {
135        return -1;
136    }
137
138    if (FALSE == bFwDnldFlag)
139    {
140        totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
141    }
142    else
143    {
144        totalBtyesToRead = FW_DNLD_HEADER_LEN;
145    }
146
147    /* Read with 2 second timeout, so that the read thread can be aborted
148       when the PN54X does not respond and we need to switch to FW download
149       mode. This should be done via a control socket instead. */
150    FD_ZERO(&rfds);
151    FD_SET((intptr_t) pDevHandle, &rfds);
152    tv.tv_sec = 2;
153    tv.tv_usec = 1;
154
155    ret_Select = select((int)((intptr_t)pDevHandle + (int)1), &rfds, NULL, NULL, &tv);
156    if (ret_Select < 0)
157    {
158        NXPLOG_TML_E("i2c select() errno : %x",errno);
159        return -1;
160    }
161    else if (ret_Select == 0)
162    {
163        NXPLOG_TML_E("i2c select() Timeout");
164        return -1;
165    }
166    else
167    {
168        ret_Read = read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead);
169        if (ret_Read > 0)
170        {
171            numRead += ret_Read;
172        }
173        else if (ret_Read == 0)
174        {
175            NXPLOG_TML_E("_i2c_read() [hdr]EOF");
176            return -1;
177        }
178        else
179        {
180            NXPLOG_TML_E("_i2c_read() [hdr] errno : %x",errno);
181            return -1;
182        }
183
184        if (FALSE == bFwDnldFlag)
185        {
186            totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
187        }
188        else
189        {
190            totalBtyesToRead = FW_DNLD_HEADER_LEN;
191        }
192
193        if(numRead < totalBtyesToRead)
194        {
195            ret_Read = read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead);
196            if (ret_Read != totalBtyesToRead - numRead)
197            {
198                NXPLOG_TML_E("_i2c_read() [hdr] errno : %x",errno);
199                return -1;
200            }
201            else
202            {
203                numRead += ret_Read;
204            }
205        }
206        if(TRUE == bFwDnldFlag)
207        {
208            totalBtyesToRead = pBuffer[FW_DNLD_LEN_OFFSET] + FW_DNLD_HEADER_LEN + CRC_LEN;
209        }
210        else
211        {
212            totalBtyesToRead = pBuffer[NORMAL_MODE_LEN_OFFSET] + NORMAL_MODE_HEADER_LEN;
213        }
214        ret_Read = read((intptr_t)pDevHandle, (pBuffer + numRead), totalBtyesToRead - numRead);
215        if (ret_Read > 0)
216        {
217            numRead += ret_Read;
218        }
219        else if (ret_Read == 0)
220        {
221            NXPLOG_TML_E("_i2c_read() [pyld] EOF");
222            return -1;
223        }
224        else
225        {
226            if(FALSE == bFwDnldFlag)
227            {
228                NXPLOG_TML_E("_i2c_read() [hdr] received");
229                phNxpNciHal_print_packet("RECV",pBuffer, NORMAL_MODE_HEADER_LEN);
230            }
231            NXPLOG_TML_E("_i2c_read() [pyld] errno : %x",errno);
232            return -1;
233        }
234    }
235    return numRead;
236}
237
238/*******************************************************************************
239**
240** Function         phTmlNfc_i2c_write
241**
242** Description      Writes requested number of bytes from given buffer into PN54X device
243**
244** Parameters       pDevHandle       - valid device handle
245**                  pBuffer          - buffer for read data
246**                  nNbBytesToWrite  - number of bytes requested to be written
247**
248** Returns          numWrote   - number of successfully written bytes
249**                  -1         - write operation failure
250**
251*******************************************************************************/
252int phTmlNfc_i2c_write(void *pDevHandle, uint8_t * pBuffer, int nNbBytesToWrite)
253{
254    int ret;
255    int numWrote = 0;
256    int i;
257    int numBytes = nNbBytesToWrite;
258    if (NULL == pDevHandle)
259    {
260        return -1;
261    }
262    if(fragmentation_enabled == I2C_FRAGMENATATION_DISABLED && nNbBytesToWrite > FRAGMENTSIZE_MAX)
263    {
264        NXPLOG_TML_E("i2c_write() data larger than maximum I2C  size,enable I2C fragmentation");
265        return -1;
266    }
267    while (numWrote < nNbBytesToWrite)
268    {
269        if(fragmentation_enabled == I2C_FRAGMENTATION_ENABLED && nNbBytesToWrite > FRAGMENTSIZE_MAX)
270        {
271            if(nNbBytesToWrite - numWrote > FRAGMENTSIZE_MAX)
272            {
273                numBytes = numWrote+ FRAGMENTSIZE_MAX;
274            }
275            else
276            {
277                numBytes = nNbBytesToWrite;
278            }
279        }
280        ret = write((intptr_t)pDevHandle, pBuffer + numWrote, numBytes - numWrote);
281        if (ret > 0)
282        {
283            numWrote += ret;
284            if(fragmentation_enabled == I2C_FRAGMENTATION_ENABLED && numWrote < nNbBytesToWrite)
285            {
286                usleep(500);
287            }
288        }
289        else if (ret == 0)
290        {
291            NXPLOG_TML_E("_i2c_write() EOF");
292            return -1;
293        }
294        else
295        {
296            NXPLOG_TML_E("_i2c_write() errno : %x",errno);
297            if (errno == EINTR || errno == EAGAIN)
298            {
299                continue;
300            }
301            return -1;
302        }
303    }
304
305    return numWrote;
306}
307
308/*******************************************************************************
309**
310** Function         phTmlNfc_i2c_reset
311**
312** Description      Reset PN54X device, using VEN pin
313**
314** Parameters       pDevHandle     - valid device handle
315**                  level          - reset level
316**
317** Returns           0   - reset operation success
318**                  -1   - reset operation failure
319**
320*******************************************************************************/
321#define PN544_SET_PWR _IOW(0xe9, 0x01, unsigned int)
322int phTmlNfc_i2c_reset(void *pDevHandle, long level)
323{
324    int ret;
325    NXPLOG_TML_D("phTmlNfc_i2c_reset(), VEN level %ld", level);
326
327    if (NULL == pDevHandle)
328    {
329        return -1;
330    }
331
332    ret = ioctl((intptr_t)pDevHandle, PN544_SET_PWR, level);
333    if(level == 2 && ret == 0)
334    {
335        bFwDnldFlag = TRUE;
336    }else{
337        bFwDnldFlag = FALSE;
338    }
339    return ret;
340}
341
342/*******************************************************************************
343**
344** Function         getDownloadFlag
345**
346** Description      Returns the current mode
347**
348** Parameters       none
349**
350** Returns           Current mode download/NCI
351*******************************************************************************/
352bool_t getDownloadFlag(void)
353{
354
355    return bFwDnldFlag;
356}
357