aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nfc/st21nfca/i2c.c
diff options
context:
space:
mode:
authorChristophe Ricard <christophe.ricard@gmail.com>2014-04-24 17:19:33 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2014-05-04 19:00:34 -0400
commitc97ffdbf51ec3f944e6661ecb16985d47c8073c7 (patch)
tree268023b014a7f74f84776729a3a28fb26848ea4f /drivers/nfc/st21nfca/i2c.c
parente1fb97b9256f383ed9553a1fc0b1576dfc88d582 (diff)
NFC: st21nfca: Improved i2c Rx data correctness check
A frame starts with ST21NFCA_SOF_EOF(0x7e) + 0x00. A frame ends with ST21NFCA_SOF_EOF(0x7e). It is possible that the i2c macrocell is stopped for other communication interfaces with highest priority(RF or SWP). This can be seen with some 0xFF data at the end of a received shdlc buffer. If this happen we need to discard the frame because the CLF will repeat it. In order to push accurate data to hci layer, we add the following fix: - Instead of looking for the first 0x7e in the frame, check that the last received byte is 0x7e. - Check that the first frame reception block start with start of frame(0x7e 0x00). If not, clear the buffer. - Check that the next frame reception block do not start with start of frame(0x7e). If so, clear the buffer. Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/nfc/st21nfca/i2c.c')
-rw-r--r--drivers/nfc/st21nfca/i2c.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c
index e29351ca7dd1..48f8e23fc321 100644
--- a/drivers/nfc/st21nfca/i2c.c
+++ b/drivers/nfc/st21nfca/i2c.c
@@ -53,6 +53,8 @@
53 53
54/* 2 bytes crc + EOF */ 54/* 2 bytes crc + EOF */
55#define ST21NFCA_FRAME_TAILROOM 3 55#define ST21NFCA_FRAME_TAILROOM 3
56#define IS_START_OF_FRAME(buf) (buf[0] == ST21NFCA_SOF_EOF && \
57 buf[1] == 0)
56 58
57#define ST21NFCA_HCI_I2C_DRIVER_NAME "st21nfca_hci_i2c" 59#define ST21NFCA_HCI_I2C_DRIVER_NAME "st21nfca_hci_i2c"
58 60
@@ -361,6 +363,7 @@ static int st21nfca_hci_i2c_read(struct st21nfca_i2c_phy *phy,
361{ 363{
362 int r, i; 364 int r, i;
363 u8 len; 365 u8 len;
366 u8 buf[ST21NFCA_HCI_LLC_MAX_PAYLOAD];
364 struct i2c_client *client = phy->i2c_dev; 367 struct i2c_client *client = phy->i2c_dev;
365 368
366 if (phy->current_read_len < ARRAY_SIZE(len_seq)) { 369 if (phy->current_read_len < ARRAY_SIZE(len_seq)) {
@@ -373,7 +376,7 @@ static int st21nfca_hci_i2c_read(struct st21nfca_i2c_phy *phy,
373 */ 376 */
374 r = 0; 377 r = 0;
375 for (i = 0; i < ARRAY_SIZE(wait_tab) && r <= 0; i++) { 378 for (i = 0; i < ARRAY_SIZE(wait_tab) && r <= 0; i++) {
376 r = i2c_master_recv(client, skb_put(skb, len), len); 379 r = i2c_master_recv(client, buf, len);
377 if (r < 0) 380 if (r < 0)
378 msleep(wait_tab[i]); 381 msleep(wait_tab[i]);
379 } 382 }
@@ -383,8 +386,28 @@ static int st21nfca_hci_i2c_read(struct st21nfca_i2c_phy *phy,
383 return -EREMOTEIO; 386 return -EREMOTEIO;
384 } 387 }
385 388
386 if (memchr(skb->data + 2, ST21NFCA_SOF_EOF, 389 /*
387 skb->len - 2) != NULL) { 390 * The first read sequence does not start with SOF.
391 * Data is corrupeted so we drop it.
392 */
393 if (!phy->current_read_len && buf[0] != ST21NFCA_SOF_EOF) {
394 skb_trim(skb, 0);
395 phy->current_read_len = 0;
396 return -EIO;
397 } else if (phy->current_read_len &&
398 IS_START_OF_FRAME(buf)) {
399 /*
400 * Previous frame transmission was interrupted and
401 * the frame got repeated.
402 * Received frame start with ST21NFCA_SOF_EOF + 00.
403 */
404 skb_trim(skb, 0);
405 phy->current_read_len = 0;
406 }
407
408 memcpy(skb_put(skb, len), buf, len);
409
410 if (skb->data[skb->len - 1] == ST21NFCA_SOF_EOF) {
388 phy->current_read_len = 0; 411 phy->current_read_len = 0;
389 return st21nfca_hci_i2c_repack(skb); 412 return st21nfca_hci_i2c_repack(skb);
390 } 413 }