From 40dac370efea8d5f2e4de61badf377637053fda7 Mon Sep 17 00:00:00 2001 From: Thierry Escande Date: Mon, 24 Jun 2013 12:02:28 +0200 Subject: NFC: Fix missing static declarations This patch fixes 3 sparse warnings: nfcsim.c:63:25: sparse: symbol 'wq' was not declared. nfcsim.c:484:12: sparse: symbol 'nfcsim_init' was not declared. nfcsim.c:525:13: sparse: symbol 'nfcsim_exit' was not declared. Reported-by: Fengguang Wu Signed-off-by: Thierry Escande Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcsim.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nfcsim.c b/drivers/nfc/nfcsim.c index c5c30fb1d7bf..9a53f13c88df 100644 --- a/drivers/nfc/nfcsim.c +++ b/drivers/nfc/nfcsim.c @@ -60,7 +60,7 @@ struct nfcsim { static struct nfcsim *dev0; static struct nfcsim *dev1; -struct workqueue_struct *wq; +static struct workqueue_struct *wq; static void nfcsim_cleanup_dev(struct nfcsim *dev, u8 shutdown) { @@ -481,7 +481,7 @@ static void nfcsim_free_device(struct nfcsim *dev) kfree(dev); } -int __init nfcsim_init(void) +static int __init nfcsim_init(void) { int rc; @@ -522,7 +522,7 @@ exit: return rc; } -void __exit nfcsim_exit(void) +static void __exit nfcsim_exit(void) { nfcsim_cleanup_dev(dev0, 1); nfcsim_cleanup_dev(dev1, 1); -- cgit v1.2.3-70-g09d2 From f1abed171fa565448d229afb814f66ab6d104d44 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 26 Jun 2013 17:53:09 +0200 Subject: NFC: pn533: Fix hardware busy loop when establishing the LLCP link By using the standard setting for the regular pn533 dongles, we no longer wait for ever for an ATR_RES. Without this, a failing ATR_REQ will put the hardware into a busy loop, constantly waiting for an ATR_RES. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index daf92ac209f8..3c169e3fdee1 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -2605,17 +2605,6 @@ static int pn533_setup(struct pn533 *dev) switch (dev->device_type) { case PN533_DEVICE_STD: - max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS; - max_retries.mx_rty_psl = 2; - max_retries.mx_rty_passive_act = - PN533_CONFIG_MAX_RETRIES_NO_RETRY; - - timing.rfu = PN533_CONFIG_TIMING_102; - timing.atr_res_timeout = PN533_CONFIG_TIMING_204; - timing.dep_timeout = PN533_CONFIG_TIMING_409; - - break; - case PN533_DEVICE_PASORI: case PN533_DEVICE_ACR122U: max_retries.mx_rty_atr = 0x2; -- cgit v1.2.3-70-g09d2 From 17e9d9d437d1bb52077e562fae9457236dbaa76f Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 26 Jun 2013 18:16:21 +0200 Subject: NFC: pn533: Fix the pn533 polling loop By turning the radio off after each failed polling try, we dramatically improve the pn533 polling loop efficiency. Without this fix, all Android phones running the broadcom NFC stack are almost never detected. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 3c169e3fdee1..fe9d4b7b6078 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -359,6 +359,7 @@ struct pn533 { struct work_struct poll_work; struct work_struct mi_work; struct work_struct tg_work; + struct work_struct rf_work; struct list_head cmd_queue; struct pn533_cmd *cmd; @@ -1660,6 +1661,53 @@ static void pn533_listen_mode_timer(unsigned long data) queue_work(dev->wq, &dev->poll_work); } +static int pn533_rf_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp) +{ + int rc = 0; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + if (IS_ERR(resp)) { + rc = PTR_ERR(resp); + + nfc_dev_err(&dev->interface->dev, "%s RF setting error %d", + __func__, rc); + + return rc; + } + + queue_work(dev->wq, &dev->poll_work); + + dev_kfree_skb(resp); + return rc; +} + +static void pn533_wq_rf(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, rf_work); + struct sk_buff *skb; + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + skb = pn533_alloc_skb(dev, 2); + if (!skb) + return; + + *skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD; + *skb_put(skb, 1) = 0; + + rc = pn533_send_cmd_async(dev, PN533_CMD_RF_CONFIGURATION, skb, + pn533_rf_complete, NULL); + if (rc < 0) { + dev_kfree_skb(skb); + nfc_dev_err(&dev->interface->dev, "RF setting error %d", rc); + } + + return; +} + static int pn533_poll_complete(struct pn533 *dev, void *arg, struct sk_buff *resp) { @@ -1705,7 +1753,8 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg, } pn533_poll_next_mod(dev); - queue_work(dev->wq, &dev->poll_work); + /* Not target found, turn radio off */ + queue_work(dev->wq, &dev->rf_work); done: dev_kfree_skb(resp); @@ -2051,6 +2100,7 @@ static int pn533_mod_to_baud(struct pn533 *dev) } } +static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf); #define PASSIVE_DATA_LEN 5 static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, u8 comm_mode, u8 *gb, size_t gb_len) @@ -2127,6 +2177,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, *arg = !comm_mode; + pn533_rf_field(dev->nfc_dev, 0); + rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb, pn533_in_dep_link_up_complete, arg); @@ -2721,6 +2773,7 @@ static int pn533_probe(struct usb_interface *interface, INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); INIT_WORK(&dev->poll_work, pn533_wq_poll); + INIT_WORK(&dev->rf_work, pn533_wq_rf); dev->wq = alloc_ordered_workqueue("pn533", 0); if (dev->wq == NULL) goto error; -- cgit v1.2.3-70-g09d2 From a94e10f7d7ce8e22d3d1cfebdfb7fe0451714799 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 28 Jun 2013 15:43:19 +0200 Subject: NFC: pn533: Request System code from SENSF_REQ Some devices are getting confused when not being asked for their system code with type F. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index fe9d4b7b6078..fa12f59cf7b9 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -257,7 +257,7 @@ static const struct pn533_poll_modulations poll_mod[] = { .initiator_data.felica = { .opcode = PN533_FELICA_OPC_SENSF_REQ, .sc = PN533_FELICA_SENSF_SC_ALL, - .rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE, + .rc = PN533_FELICA_SENSF_RC_SYSTEM_CODE, .tsn = 0x03, }, }, @@ -270,7 +270,7 @@ static const struct pn533_poll_modulations poll_mod[] = { .initiator_data.felica = { .opcode = PN533_FELICA_OPC_SENSF_REQ, .sc = PN533_FELICA_SENSF_SC_ALL, - .rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE, + .rc = PN533_FELICA_SENSF_RC_SYSTEM_CODE, .tsn = 0x03, }, }, -- cgit v1.2.3-70-g09d2 From 5eef4845619b88957349415b7b1498e00220fa2b Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 1 Jul 2013 10:58:12 +0200 Subject: NFC: pn533: Unconditionaly select the highest p2p bit rate p2p devices must be able to support 424 kbps, so we should always select that bitrate in initiator mode. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 56 +++++++++++++++++++---------------------------------- 1 file changed, 20 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index fa12f59cf7b9..ff3e19dcc7c5 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -2086,20 +2086,6 @@ error: return rc; } -static int pn533_mod_to_baud(struct pn533 *dev) -{ - switch (dev->poll_mod_curr) { - case PN533_POLL_MOD_106KBPS_A: - return 0; - case PN533_POLL_MOD_212KBPS_FELICA: - return 1; - case PN533_POLL_MOD_424KBPS_FELICA: - return 2; - default: - return -EINVAL; - } -} - static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf); #define PASSIVE_DATA_LEN 5 static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, @@ -2107,8 +2093,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, { struct pn533 *dev = nfc_get_drvdata(nfc_dev); struct sk_buff *skb; - int rc, baud, skb_len; - u8 *next, *arg; + int rc, skb_len; + u8 *next, *arg, nfcid3[NFC_NFCID3_MAXSIZE]; u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3}; @@ -2126,41 +2112,39 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, return -EBUSY; } - baud = pn533_mod_to_baud(dev); - if (baud < 0) { - nfc_dev_err(&dev->interface->dev, - "Invalid curr modulation %d", dev->poll_mod_curr); - return baud; - } - skb_len = 3 + gb_len; /* ActPass + BR + Next */ - if (comm_mode == NFC_COMM_PASSIVE) - skb_len += PASSIVE_DATA_LEN; + skb_len += PASSIVE_DATA_LEN; - if (target && target->nfcid2_len) - skb_len += NFC_NFCID3_MAXSIZE; + /* NFCID3 */ + skb_len += NFC_NFCID3_MAXSIZE; + if (target && !target->nfcid2_len) { + nfcid3[0] = 0x1; + nfcid3[1] = 0xfe; + get_random_bytes(nfcid3 + 2, 6); + } skb = pn533_alloc_skb(dev, skb_len); if (!skb) return -ENOMEM; *skb_put(skb, 1) = !comm_mode; /* ActPass */ - *skb_put(skb, 1) = baud; /* Baud rate */ + *skb_put(skb, 1) = 0x02; /* 424 kbps */ next = skb_put(skb, 1); /* Next */ *next = 0; - if (comm_mode == NFC_COMM_PASSIVE && baud > 0) { - memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, - PASSIVE_DATA_LEN); - *next |= 1; - } + /* Copy passive data */ + memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, PASSIVE_DATA_LEN); + *next |= 1; - if (target && target->nfcid2_len) { + /* Copy NFCID3 (which is NFCID2 from SENSF_RES) */ + if (target && target->nfcid2_len) memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), target->nfcid2, target->nfcid2_len); - *next |= 2; - } + else + memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), nfcid3, + NFC_NFCID3_MAXSIZE); + *next |= 2; if (gb != NULL && gb_len > 0) { memcpy(skb_put(skb, gb_len), gb, gb_len); -- cgit v1.2.3-70-g09d2 From 3a8eab39ac53f2d35d663634e16b486e8a5a65a9 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 1 Jul 2013 17:26:58 +0200 Subject: NFC: pn533: Enable AUTO RFCA The AUTO RFCA bit forbids the pn533 chipset to turn its radio on whenever an external field is present. Without this bit set, some devices seems to get over flood by the pn533 rf field and thus become hardly detectable. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index ff3e19dcc7c5..125d995c11a9 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -168,8 +168,9 @@ struct pn533_fw_version { #define PN533_CFGITEM_MAX_RETRIES 0x05 #define PN533_CFGITEM_PASORI 0x82 -#define PN533_CFGITEM_RF_FIELD_ON 0x1 -#define PN533_CFGITEM_RF_FIELD_OFF 0x0 +#define PN533_CFGITEM_RF_FIELD_AUTO_RFCA 0x2 +#define PN533_CFGITEM_RF_FIELD_ON 0x1 +#define PN533_CFGITEM_RF_FIELD_OFF 0x0 #define PN533_CONFIG_TIMING_102 0xb #define PN533_CONFIG_TIMING_204 0xc @@ -1696,7 +1697,7 @@ static void pn533_wq_rf(struct work_struct *work) return; *skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD; - *skb_put(skb, 1) = 0; + *skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD_AUTO_RFCA; rc = pn533_send_cmd_async(dev, PN533_CMD_RF_CONFIGURATION, skb, pn533_rf_complete, NULL); @@ -2598,6 +2599,8 @@ static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf) u8 rf_field = !!rf; int rc; + rf_field |= PN533_CFGITEM_RF_FIELD_AUTO_RFCA; + rc = pn533_set_configuration(dev, PN533_CFGITEM_RF_FIELD, (u8 *)&rf_field, 1); if (rc) { -- cgit v1.2.3-70-g09d2 From 1575b9d8668f4ecf2648a08751313c826fb6a6e9 Mon Sep 17 00:00:00 2001 From: Olivier Guiter Date: Thu, 13 Jun 2013 15:43:27 +0200 Subject: NFC: pn533: Add extended information frame decoding support Extended Information frames are slightly different from standard frames as they can (theorically) handle datas up tu 64kB. PN533 firmware only supports packet data up to 265 (incl. TFI byte) This kind of frame are used when the pn533 wants to exchange more than 255 bytes, and this patch handles the reception of such frames. Signed-off-by: Olivier Guiter Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 85 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 125d995c11a9..ae0fa9ee169d 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -84,11 +84,17 @@ MODULE_DEVICE_TABLE(usb, pn533_table); /* How much time we spend listening for initiators */ #define PN533_LISTEN_TIME 2 -/* Standard pn533 frame definitions */ +/* Standard pn533 frame definitions (standard and extended)*/ #define PN533_STD_FRAME_HEADER_LEN (sizeof(struct pn533_std_frame) \ + 2) /* data[0] TFI, data[1] CC */ #define PN533_STD_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/ +#define PN533_EXT_FRAME_HEADER_LEN (sizeof(struct pn533_ext_frame) \ + + 2) /* data[0] TFI, data[1] CC */ + +#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262 +#define PN533_CMD_DATAFRAME_MAXLEN 240 /* max data length (send) */ + /* * Max extended frame payload len, excluding TFI and CC * which are already in PN533_FRAME_HEADER_LEN. @@ -99,6 +105,10 @@ MODULE_DEVICE_TABLE(usb, pn533_table); Postamble (1) */ #define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen]) #define PN533_STD_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1]) +/* Half start code (3), LEN (4) should be 0xffff for extended frame */ +#define PN533_STD_IS_EXTENDED(hdr) ((hdr)->datalen == 0xFF \ + && (hdr)->datalen_checksum == 0xFF) +#define PN533_EXT_FRAME_CHECKSUM(f) (f->data[be16_to_cpu(f->datalen)]) /* start of frame */ #define PN533_STD_FRAME_SOF 0x00FF @@ -124,7 +134,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table); #define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83 /* PN533 Commands */ -#define PN533_STD_FRAME_CMD(f) (f->data[1]) +#define PN533_FRAME_CMD(f) (f->data[1]) #define PN533_CMD_GET_FIRMWARE_VERSION 0x02 #define PN533_CMD_RF_CONFIGURATION 0x32 @@ -406,6 +416,15 @@ struct pn533_std_frame { u8 data[]; } __packed; +struct pn533_ext_frame { /* Extended Information frame */ + u8 preamble; + __be16 start_frame; + __be16 eif_flag; /* fixed to 0xFFFF */ + __be16 datalen; + u8 datalen_checksum; + u8 data[]; +} __packed; + struct pn533_frame_ops { void (*tx_frame_init)(void *frame, u8 cmd_code); void (*tx_frame_finish)(void *frame); @@ -513,7 +532,7 @@ static u8 pn533_acr122_get_cmd_code(void *frame) { struct pn533_acr122_rx_frame *f = frame; - return PN533_STD_FRAME_CMD(f); + return PN533_FRAME_CMD(f); } static struct pn533_frame_ops pn533_acr122_frame_ops = { @@ -532,6 +551,12 @@ static struct pn533_frame_ops pn533_acr122_frame_ops = { .get_cmd_code = pn533_acr122_get_cmd_code, }; +/* The rule: value(high byte) + value(low byte) + checksum = 0 */ +static inline u8 pn533_ext_checksum(u16 value) +{ + return ~(u8)(((value & 0xFF00) >> 8) + (u8)(value & 0xFF)) + 1; +} + /* The rule: value + checksum = 0 */ static inline u8 pn533_std_checksum(u8 value) { @@ -557,7 +582,7 @@ static void pn533_std_tx_frame_init(void *_frame, u8 cmd_code) frame->preamble = 0; frame->start_frame = cpu_to_be16(PN533_STD_FRAME_SOF); PN533_STD_FRAME_IDENTIFIER(frame) = PN533_STD_FRAME_DIR_OUT; - PN533_STD_FRAME_CMD(frame) = cmd_code; + PN533_FRAME_CMD(frame) = cmd_code; frame->datalen = 2; } @@ -583,18 +608,35 @@ static void pn533_std_tx_update_payload_len(void *_frame, int len) static bool pn533_std_rx_frame_is_valid(void *_frame) { u8 checksum; - struct pn533_std_frame *frame = _frame; + struct pn533_std_frame *stdf = _frame; - if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF)) + if (stdf->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF)) return false; - checksum = pn533_std_checksum(frame->datalen); - if (checksum != frame->datalen_checksum) - return false; + if (likely(!PN533_STD_IS_EXTENDED(stdf))) { + /* Standard frame code */ - checksum = pn533_std_data_checksum(frame->data, frame->datalen); - if (checksum != PN533_STD_FRAME_CHECKSUM(frame)) - return false; + checksum = pn533_std_checksum(stdf->datalen); + if (checksum != stdf->datalen_checksum) + return false; + + checksum = pn533_std_data_checksum(stdf->data, stdf->datalen); + if (checksum != PN533_STD_FRAME_CHECKSUM(stdf)) + return false; + } else { + /* Extended */ + struct pn533_ext_frame *eif = _frame; + + checksum = pn533_ext_checksum(be16_to_cpu(eif->datalen)); + if (checksum != eif->datalen_checksum) + return false; + + /* check data checksum */ + checksum = pn533_std_data_checksum(eif->data, + be16_to_cpu(eif->datalen)); + if (checksum != PN533_EXT_FRAME_CHECKSUM(eif)) + return false; + } return true; } @@ -614,6 +656,14 @@ static inline int pn533_std_rx_frame_size(void *frame) { struct pn533_std_frame *f = frame; + /* check for Extended Information frame */ + if (PN533_STD_IS_EXTENDED(f)) { + struct pn533_ext_frame *eif = frame; + + return sizeof(struct pn533_ext_frame) + + be16_to_cpu(eif->datalen) + PN533_STD_FRAME_TAIL_LEN; + } + return sizeof(struct pn533_std_frame) + f->datalen + PN533_STD_FRAME_TAIL_LEN; } @@ -621,8 +671,12 @@ static inline int pn533_std_rx_frame_size(void *frame) static u8 pn533_std_get_cmd_code(void *frame) { struct pn533_std_frame *f = frame; + struct pn533_ext_frame *eif = frame; - return PN533_STD_FRAME_CMD(f); + if (PN533_STD_IS_EXTENDED(f)) + return PN533_FRAME_CMD(eif); + else + return PN533_FRAME_CMD(f); } static struct pn533_frame_ops pn533_std_frame_ops = { @@ -690,6 +744,11 @@ static void pn533_recv_response(struct urb *urb) goto sched_wq; } + if (PN533_STD_IS_EXTENDED((struct pn533_std_frame *)in_frame)) + dev->ops->rx_header_len = PN533_EXT_FRAME_HEADER_LEN; + else + dev->ops->rx_header_len = PN533_STD_FRAME_HEADER_LEN; + sched_wq: queue_work(dev->wq, &dev->cmd_complete_work); } -- cgit v1.2.3-70-g09d2 From 963a82e07d4e1f95fc423d53912ac0a7fe643b1c Mon Sep 17 00:00:00 2001 From: Olivier Guiter Date: Thu, 13 Jun 2013 13:43:28 +0000 Subject: NFC: pn533: Split large Tx frames in chunks On sending large frames (size > 262), we split it in multiple chunks and send them asynchronously with MI bit. Signed-off-by: Olivier Guiter Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 130 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index ae0fa9ee169d..f06ef7c49f84 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -363,12 +363,14 @@ struct pn533 { struct urb *in_urb; struct sk_buff_head resp_q; + struct sk_buff_head fragment_skb; struct workqueue_struct *wq; struct work_struct cmd_work; struct work_struct cmd_complete_work; struct work_struct poll_work; - struct work_struct mi_work; + struct work_struct mi_rx_work; + struct work_struct mi_tx_work; struct work_struct tg_work; struct work_struct rf_work; @@ -378,6 +380,7 @@ struct pn533 { struct mutex cmd_lock; /* protects cmd queue */ void *cmd_complete_mi_arg; + void *cmd_complete_dep_arg; struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1]; u8 poll_mod_count; @@ -2328,7 +2331,15 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, if (mi) { dev->cmd_complete_mi_arg = arg; - queue_work(dev->wq, &dev->mi_work); + queue_work(dev->wq, &dev->mi_rx_work); + return -EINPROGRESS; + } + + /* Prepare for the next round */ + if (skb_queue_len(&dev->fragment_skb) > 0) { + dev->cmd_complete_dep_arg = arg; + queue_work(dev->wq, &dev->mi_tx_work); + return -EINPROGRESS; } @@ -2349,6 +2360,50 @@ _error: return rc; } +/* Split the Tx skb into small chunks */ +static int pn533_fill_fragment_skbs(struct pn533 *dev, struct sk_buff *skb) +{ + struct sk_buff *frag; + int frag_size; + + do { + /* Remaining size */ + if (skb->len > PN533_CMD_DATAFRAME_MAXLEN) + frag_size = PN533_CMD_DATAFRAME_MAXLEN; + else + frag_size = skb->len; + + /* Allocate and reserve */ + frag = pn533_alloc_skb(dev, frag_size); + if (!frag) { + skb_queue_purge(&dev->fragment_skb); + break; + } + + /* Reserve the TG/MI byte */ + skb_reserve(frag, 1); + + /* MI + TG */ + if (frag_size == PN533_CMD_DATAFRAME_MAXLEN) + *skb_push(frag, sizeof(u8)) = (PN533_CMD_MI_MASK | 1); + else + *skb_push(frag, sizeof(u8)) = 1; /* TG */ + + memcpy(skb_put(frag, frag_size), skb->data, frag_size); + + /* Reduce the size of incoming buffer */ + skb_pull(skb, frag_size); + + /* Add this to skb_queue */ + skb_queue_tail(&dev->fragment_skb, frag); + + } while (skb->len > 0); + + dev_kfree_skb(skb); + + return skb_queue_len(&dev->fragment_skb); +} + static int pn533_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context) @@ -2359,15 +2414,6 @@ static int pn533_transceive(struct nfc_dev *nfc_dev, nfc_dev_dbg(&dev->interface->dev, "%s", __func__); - if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) { - /* TODO: Implement support to multi-part data exchange */ - nfc_dev_err(&dev->interface->dev, - "Data length greater than the max allowed: %d", - PN533_CMD_DATAEXCH_DATA_MAXLEN); - rc = -ENOSYS; - goto error; - } - if (!dev->tgt_active_prot) { nfc_dev_err(&dev->interface->dev, "Can't exchange data if there is no active target"); @@ -2395,7 +2441,20 @@ static int pn533_transceive(struct nfc_dev *nfc_dev, break; } default: - *skb_push(skb, sizeof(u8)) = 1; /*TG*/ + /* jumbo frame ? */ + if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) { + rc = pn533_fill_fragment_skbs(dev, skb); + if (rc <= 0) + goto error; + + skb = skb_dequeue(&dev->fragment_skb); + if (!skb) { + rc = -EIO; + goto error; + } + } else { + *skb_push(skb, sizeof(u8)) = 1; /* TG */ + } rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE, skb, pn533_data_exchange_complete, @@ -2466,7 +2525,7 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) static void pn533_wq_mi_recv(struct work_struct *work) { - struct pn533 *dev = container_of(work, struct pn533, mi_work); + struct pn533 *dev = container_of(work, struct pn533, mi_rx_work); struct sk_buff *skb; int rc; @@ -2514,6 +2573,61 @@ error: queue_work(dev->wq, &dev->cmd_work); } +static void pn533_wq_mi_send(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, mi_tx_work); + struct sk_buff *skb; + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + /* Grab the first skb in the queue */ + skb = skb_dequeue(&dev->fragment_skb); + + if (skb == NULL) { /* No more data */ + /* Reset the queue for future use */ + skb_queue_head_init(&dev->fragment_skb); + goto error; + } + + switch (dev->device_type) { + case PN533_DEVICE_PASORI: + if (dev->tgt_active_prot != NFC_PROTO_FELICA) { + rc = -EIO; + break; + } + + rc = pn533_send_cmd_direct_async(dev, PN533_CMD_IN_COMM_THRU, + skb, + pn533_data_exchange_complete, + dev->cmd_complete_dep_arg); + + break; + + default: + /* Still some fragments? */ + rc = pn533_send_cmd_direct_async(dev,PN533_CMD_IN_DATA_EXCHANGE, + skb, + pn533_data_exchange_complete, + dev->cmd_complete_dep_arg); + + break; + } + + if (rc == 0) /* success */ + return; + + nfc_dev_err(&dev->interface->dev, + "Error %d when trying to perform data_exchange", rc); + + dev_kfree_skb(skb); + kfree(dev->cmd_complete_dep_arg); + +error: + pn533_send_ack(dev, GFP_KERNEL); + queue_work(dev->wq, &dev->cmd_work); +} + static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, u8 cfgdata_len) { @@ -2816,7 +2930,8 @@ static int pn533_probe(struct usb_interface *interface, INIT_WORK(&dev->cmd_work, pn533_wq_cmd); INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete); - INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); + INIT_WORK(&dev->mi_rx_work, pn533_wq_mi_recv); + INIT_WORK(&dev->mi_tx_work, pn533_wq_mi_send); INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); INIT_WORK(&dev->poll_work, pn533_wq_poll); INIT_WORK(&dev->rf_work, pn533_wq_rf); @@ -2829,6 +2944,7 @@ static int pn533_probe(struct usb_interface *interface, dev->listen_timer.function = pn533_listen_mode_timer; skb_queue_head_init(&dev->resp_q); + skb_queue_head_init(&dev->fragment_skb); INIT_LIST_HEAD(&dev->cmd_queue); -- cgit v1.2.3-70-g09d2 From 56a63c82cf82eb491af05759d9e9f9b97ca36bc2 Mon Sep 17 00:00:00 2001 From: Olivier Guiter Date: Thu, 13 Jun 2013 13:43:29 +0000 Subject: NFC: pn533: Store the correct frame size (normal vs ext) The extended information frame are sent by PN533 to exchange frames larger than 255 bytes. These extended frame are very close from the standard ones except for the header size length. On each incoming frame, we set the correct header length, and we do that only for the standard pn533 chipsets as the acr122 does not seem to support extended frames properly. Signed-off-by: Olivier Guiter Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index f06ef7c49f84..2f1ebbd8cba6 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -435,7 +435,7 @@ struct pn533_frame_ops { int tx_header_len; int tx_tail_len; - bool (*rx_is_frame_valid)(void *frame); + bool (*rx_is_frame_valid)(void *frame, struct pn533 *dev); int (*rx_frame_size)(void *frame); int rx_header_len; int rx_tail_len; @@ -510,7 +510,7 @@ static void pn533_acr122_tx_update_payload_len(void *_frame, int len) frame->datalen += len; } -static bool pn533_acr122_is_rx_frame_valid(void *_frame) +static bool pn533_acr122_is_rx_frame_valid(void *_frame, struct pn533 *dev) { struct pn533_acr122_rx_frame *frame = _frame; @@ -608,7 +608,7 @@ static void pn533_std_tx_update_payload_len(void *_frame, int len) frame->datalen += len; } -static bool pn533_std_rx_frame_is_valid(void *_frame) +static bool pn533_std_rx_frame_is_valid(void *_frame, struct pn533 *dev) { u8 checksum; struct pn533_std_frame *stdf = _frame; @@ -618,6 +618,7 @@ static bool pn533_std_rx_frame_is_valid(void *_frame) if (likely(!PN533_STD_IS_EXTENDED(stdf))) { /* Standard frame code */ + dev->ops->rx_header_len = PN533_STD_FRAME_HEADER_LEN; checksum = pn533_std_checksum(stdf->datalen); if (checksum != stdf->datalen_checksum) @@ -630,6 +631,8 @@ static bool pn533_std_rx_frame_is_valid(void *_frame) /* Extended */ struct pn533_ext_frame *eif = _frame; + dev->ops->rx_header_len = PN533_EXT_FRAME_HEADER_LEN; + checksum = pn533_ext_checksum(be16_to_cpu(eif->datalen)); if (checksum != eif->datalen_checksum) return false; @@ -734,7 +737,7 @@ static void pn533_recv_response(struct urb *urb) print_hex_dump_debug("PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, in_frame, dev->ops->rx_frame_size(in_frame), false); - if (!dev->ops->rx_is_frame_valid(in_frame)) { + if (!dev->ops->rx_is_frame_valid(in_frame, dev)) { nfc_dev_err(&dev->interface->dev, "Received an invalid frame"); cmd->status = -EIO; goto sched_wq; @@ -747,11 +750,6 @@ static void pn533_recv_response(struct urb *urb) goto sched_wq; } - if (PN533_STD_IS_EXTENDED((struct pn533_std_frame *)in_frame)) - dev->ops->rx_header_len = PN533_EXT_FRAME_HEADER_LEN; - else - dev->ops->rx_header_len = PN533_STD_FRAME_HEADER_LEN; - sched_wq: queue_work(dev->wq, &dev->cmd_complete_work); } -- cgit v1.2.3-70-g09d2 From 46f793b0413cfb234ca4faf7e598f24967e1fd3b Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 3 Jul 2013 14:50:36 +0200 Subject: NFC: pn533: Add delay between each poll frame It seems that some pn533 firmwares go belly up when being asked to send poll frames too frequently. Adding a 10ms delay between each of them calm the chip down and prevent it from crashing. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 2f1ebbd8cba6..9f3868b0170b 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -83,6 +83,8 @@ MODULE_DEVICE_TABLE(usb, pn533_table); /* How much time we spend listening for initiators */ #define PN533_LISTEN_TIME 2 +/* Delay between each poll frame (ms) */ +#define PN533_POLL_INTERVAL 10 /* Standard pn533 frame definitions (standard and extended)*/ #define PN533_STD_FRAME_HEADER_LEN (sizeof(struct pn533_std_frame) \ @@ -368,7 +370,7 @@ struct pn533 { struct workqueue_struct *wq; struct work_struct cmd_work; struct work_struct cmd_complete_work; - struct work_struct poll_work; + struct delayed_work poll_work; struct work_struct mi_rx_work; struct work_struct mi_tx_work; struct work_struct tg_work; @@ -1719,7 +1721,8 @@ static void pn533_listen_mode_timer(unsigned long data) pn533_poll_next_mod(dev); - queue_work(dev->wq, &dev->poll_work); + queue_delayed_work(dev->wq, &dev->poll_work, + msecs_to_jiffies(PN533_POLL_INTERVAL)); } static int pn533_rf_complete(struct pn533 *dev, void *arg, @@ -1738,7 +1741,8 @@ static int pn533_rf_complete(struct pn533 *dev, void *arg, return rc; } - queue_work(dev->wq, &dev->poll_work); + queue_delayed_work(dev->wq, &dev->poll_work, + msecs_to_jiffies(PN533_POLL_INTERVAL)); dev_kfree_skb(resp); return rc; @@ -1880,7 +1884,7 @@ static int pn533_send_poll_frame(struct pn533 *dev) static void pn533_wq_poll(struct work_struct *work) { - struct pn533 *dev = container_of(work, struct pn533, poll_work); + struct pn533 *dev = container_of(work, struct pn533, poll_work.work); struct pn533_poll_modulations *cur_mod; int rc; @@ -1955,6 +1959,7 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev) } pn533_abort_cmd(dev, GFP_KERNEL); + flush_delayed_work(&dev->poll_work); pn533_poll_reset_mod_list(dev); } @@ -2931,7 +2936,7 @@ static int pn533_probe(struct usb_interface *interface, INIT_WORK(&dev->mi_rx_work, pn533_wq_mi_recv); INIT_WORK(&dev->mi_tx_work, pn533_wq_mi_send); INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); - INIT_WORK(&dev->poll_work, pn533_wq_poll); + INIT_DELAYED_WORK(&dev->poll_work, pn533_wq_poll); INIT_WORK(&dev->rf_work, pn533_wq_rf); dev->wq = alloc_ordered_workqueue("pn533", 0); if (dev->wq == NULL) @@ -3044,6 +3049,7 @@ static void pn533_disconnect(struct usb_interface *interface) usb_kill_urb(dev->in_urb); usb_kill_urb(dev->out_urb); + flush_delayed_work(&dev->poll_work); destroy_workqueue(dev->wq); skb_queue_purge(&dev->resp_q); -- cgit v1.2.3-70-g09d2 From dfccd0f580445d176acea174175b3e6518cc91f7 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 3 Jul 2013 15:14:17 +0200 Subject: NFC: pn533: Add some polling entropy By not always starting the polling loop from the same modulation, we avoid entering infinite loops where devices exporting 2 targets (on 2 different modulations) get the same target activated over and over. If this target is not readable (e.g. a wallet emulating a tag), we will stay in an error loop for ever. Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 9f3868b0170b..5df730be88a3 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1913,6 +1913,7 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev, u32 im_protocols, u32 tm_protocols) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); + u8 rand_mod; nfc_dev_dbg(&dev->interface->dev, "%s: im protocols 0x%x tm protocols 0x%x", @@ -1936,11 +1937,15 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev, tm_protocols = 0; } - dev->poll_mod_curr = 0; pn533_poll_create_mod_list(dev, im_protocols, tm_protocols); dev->poll_protocols = im_protocols; dev->listen_protocols = tm_protocols; + /* Do not always start polling from the same modulation */ + get_random_bytes(&rand_mod, sizeof(rand_mod)); + rand_mod %= dev->poll_mod_count; + dev->poll_mod_curr = rand_mod; + return pn533_send_poll_frame(dev); } -- cgit v1.2.3-70-g09d2 From eab10b71a7d62d7cc6db631dba448f1d84df9b53 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Fri, 19 Jul 2013 14:57:13 +0200 Subject: NFC: pn544: i2c: Add firmware download mode power-on support This is in preparation for pn544-i2c firmware download feature, where we need to know if we're in regular or firmware upload mode. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544/i2c.c | 14 +++++++++++--- drivers/nfc/pn544/pn544.c | 3 --- drivers/nfc/pn544/pn544.h | 3 +++ 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index 8cf64c19f022..e09c8982596c 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -65,6 +65,7 @@ struct pn544_i2c_phy { unsigned int en_polarity; int powered; + int run_mode; int hard_fault; /* * < 0 if hardware error occured (e.g. i2c err) @@ -122,15 +123,22 @@ out: gpio_set_value(phy->gpio_en, !phy->en_polarity); } +static void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode) +{ + gpio_set_value(phy->gpio_fw, run_mode == PN544_FW_MODE ? 1 : 0); + gpio_set_value(phy->gpio_en, phy->en_polarity); + usleep_range(10000, 15000); + + phy->run_mode = run_mode; +} + static int pn544_hci_i2c_enable(void *phy_id) { struct pn544_i2c_phy *phy = phy_id; pr_info(DRIVER_DESC ": %s\n", __func__); - gpio_set_value(phy->gpio_fw, 0); - gpio_set_value(phy->gpio_en, phy->en_polarity); - usleep_range(10000, 15000); + pn544_hci_i2c_enable_mode(phy, PN544_HCI_MODE); phy->powered = 1; diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index 0d17da7675b7..1d4b38c036fb 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -31,9 +31,6 @@ /* Timing restrictions (ms) */ #define PN544_HCI_RESETVEN_TIME 30 -#define HCI_MODE 0 -#define FW_MODE 1 - enum pn544_state { PN544_ST_COLD, PN544_ST_FW_READY, diff --git a/drivers/nfc/pn544/pn544.h b/drivers/nfc/pn544/pn544.h index f47c6454914b..d689f0ac64aa 100644 --- a/drivers/nfc/pn544/pn544.h +++ b/drivers/nfc/pn544/pn544.h @@ -24,6 +24,9 @@ #define DRIVER_DESC "HCI NFC driver for PN544" +#define PN544_HCI_MODE 0 +#define PN544_FW_MODE 1 + int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, int phy_headroom, int phy_tailroom, int phy_payload, struct nfc_hci_dev **hdev); -- cgit v1.2.3-70-g09d2 From 8bd7fc89958c2f23a5c5d0113ff65713683041ea Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Fri, 19 Jul 2013 14:58:39 +0200 Subject: NFC: pn544: Add firmware operations hci ops The firmware operation callback is passed by the physical layer to the hci driver during probe. All the driver does is to store it and call it when the fw_upload hci ops is invoked. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544/i2c.c | 2 +- drivers/nfc/pn544/mei.c | 2 +- drivers/nfc/pn544/pn544.c | 17 ++++++++++++++++- drivers/nfc/pn544/pn544.h | 4 +++- 4 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index e09c8982596c..017dc61effc8 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -428,7 +428,7 @@ static int pn544_hci_i2c_probe(struct i2c_client *client, r = pn544_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME, PN544_I2C_FRAME_HEADROOM, PN544_I2C_FRAME_TAILROOM, - PN544_HCI_I2C_LLC_MAX_PAYLOAD, &phy->hdev); + PN544_HCI_I2C_LLC_MAX_PAYLOAD, NULL, &phy->hdev); if (r < 0) goto err_hci; diff --git a/drivers/nfc/pn544/mei.c b/drivers/nfc/pn544/mei.c index b5d3d18179eb..ee67de50c36f 100644 --- a/drivers/nfc/pn544/mei.c +++ b/drivers/nfc/pn544/mei.c @@ -45,7 +45,7 @@ static int pn544_mei_probe(struct mei_cl_device *device, r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME, MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, - &phy->hdev); + NULL, &phy->hdev); if (r < 0) { nfc_mei_phy_free(phy); diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index 1d4b38c036fb..078e62feba17 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -127,6 +127,8 @@ struct pn544_hci_info { int async_cb_type; data_exchange_cb_t async_cb; void *async_cb_context; + + fw_download_t fw_download; }; static int pn544_hci_open(struct nfc_hci_dev *hdev) @@ -779,6 +781,17 @@ exit: return r; } +static int pn544_hci_fw_download(struct nfc_hci_dev *hdev, + const char *firmware_name) +{ + struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); + + if (info->fw_download == NULL) + return -ENOTSUPP; + + return info->fw_download(info->phy_id, firmware_name); +} + static struct nfc_hci_ops pn544_hci_ops = { .open = pn544_hci_open, .close = pn544_hci_close, @@ -793,11 +806,12 @@ static struct nfc_hci_ops pn544_hci_ops = { .tm_send = pn544_hci_tm_send, .check_presence = pn544_hci_check_presence, .event_received = pn544_hci_event_received, + .fw_download = pn544_hci_fw_download, }; int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, int phy_headroom, int phy_tailroom, int phy_payload, - struct nfc_hci_dev **hdev) + fw_download_t fw_download, struct nfc_hci_dev **hdev) { struct pn544_hci_info *info; u32 protocols; @@ -813,6 +827,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, info->phy_ops = phy_ops; info->phy_id = phy_id; + info->fw_download = fw_download; info->state = PN544_ST_COLD; mutex_init(&info->info_lock); diff --git a/drivers/nfc/pn544/pn544.h b/drivers/nfc/pn544/pn544.h index d689f0ac64aa..01020e585443 100644 --- a/drivers/nfc/pn544/pn544.h +++ b/drivers/nfc/pn544/pn544.h @@ -27,9 +27,11 @@ #define PN544_HCI_MODE 0 #define PN544_FW_MODE 1 +typedef int (*fw_download_t)(void *context, const char *firmware_name); + int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, int phy_headroom, int phy_tailroom, int phy_payload, - struct nfc_hci_dev **hdev); + fw_download_t fw_download, struct nfc_hci_dev **hdev); void pn544_hci_remove(struct nfc_hci_dev *hdev); #endif /* __LOCAL_PN544_H_ */ -- cgit v1.2.3-70-g09d2 From 06c660340f1e142b607541ece3520fff3f5d2c39 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Fri, 19 Jul 2013 14:59:45 +0200 Subject: NFC: pn544: i2c: Add firmware download implementation for pn544 The pn544 can enter a firmware update mode where firmware blobs can be pushed through the i2c line and flashed on the target. A special command allows to verify that blobs are correctly flashed and this is what we do for every downloaded firmware blob. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544/i2c.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 334 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index 017dc61effc8..01e27d4bdd0d 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -25,11 +25,14 @@ #include #include #include - +#include +#include +#include #include #include #include +#include #include "pn544.h" @@ -55,6 +58,58 @@ MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table); #define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c" +#define PN544_FW_CMD_WRITE 0x08 +#define PN544_FW_CMD_CHECK 0x06 + +struct pn544_i2c_fw_frame_write { + u8 cmd; + u16 be_length; + u8 be_dest_addr[3]; + u16 be_datalen; + u8 data[]; +} __packed; + +struct pn544_i2c_fw_frame_check { + u8 cmd; + u16 be_length; + u8 be_start_addr[3]; + u16 be_datalen; + u16 be_crc; +} __packed; + +struct pn544_i2c_fw_frame_response { + u8 status; + u16 be_length; +} __packed; + +struct pn544_i2c_fw_blob { + u32 be_size; + u32 be_destaddr; + u8 data[]; +}; + +#define PN544_FW_CMD_RESULT_TIMEOUT 0x01 +#define PN544_FW_CMD_RESULT_BAD_CRC 0x02 +#define PN544_FW_CMD_RESULT_ACCESS_DENIED 0x08 +#define PN544_FW_CMD_RESULT_PROTOCOL_ERROR 0x0B +#define PN544_FW_CMD_RESULT_INVALID_PARAMETER 0x11 +#define PN544_FW_CMD_RESULT_INVALID_LENGTH 0x18 +#define PN544_FW_CMD_RESULT_WRITE_FAILED 0x74 + +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) + +#define PN544_FW_WRITE_BUFFER_MAX_LEN 0x9f7 +#define PN544_FW_I2C_MAX_PAYLOAD PN544_HCI_I2C_LLC_MAX_SIZE +#define PN544_FW_I2C_WRITE_FRAME_HEADER_LEN 8 +#define PN544_FW_I2C_WRITE_DATA_MAX_LEN MIN((PN544_FW_I2C_MAX_PAYLOAD -\ + PN544_FW_I2C_WRITE_FRAME_HEADER_LEN),\ + PN544_FW_WRITE_BUFFER_MAX_LEN) + +#define FW_WORK_STATE_IDLE 1 +#define FW_WORK_STATE_START 2 +#define FW_WORK_STATE_WAIT_WRITE_ANSWER 3 +#define FW_WORK_STATE_WAIT_CHECK_ANSWER 4 + struct pn544_i2c_phy { struct i2c_client *i2c_dev; struct nfc_hci_dev *hdev; @@ -64,6 +119,16 @@ struct pn544_i2c_phy { unsigned int gpio_fw; unsigned int en_polarity; + struct work_struct fw_work; + int fw_work_state; + char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1]; + const struct firmware *fw; + u32 fw_blob_dest_addr; + size_t fw_blob_size; + const u8 *fw_blob_data; + size_t fw_written; + int fw_cmd_result; + int powered; int run_mode; @@ -313,6 +378,42 @@ flush: return r; } +static int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy) +{ + int r; + struct pn544_i2c_fw_frame_response response; + struct i2c_client *client = phy->i2c_dev; + + r = i2c_master_recv(client, (char *) &response, sizeof(response)); + if (r != sizeof(response)) { + dev_err(&client->dev, "cannot read fw status\n"); + return -EIO; + } + + usleep_range(3000, 6000); + + switch (response.status) { + case 0: + return 0; + case PN544_FW_CMD_RESULT_TIMEOUT: + return -ETIMEDOUT; + case PN544_FW_CMD_RESULT_BAD_CRC: + return -ENODATA; + case PN544_FW_CMD_RESULT_ACCESS_DENIED: + return -EACCES; + case PN544_FW_CMD_RESULT_PROTOCOL_ERROR: + return -EPROTO; + case PN544_FW_CMD_RESULT_INVALID_PARAMETER: + return -EINVAL; + case PN544_FW_CMD_RESULT_INVALID_LENGTH: + return -EBADMSG; + case PN544_FW_CMD_RESULT_WRITE_FAILED: + return -EIO; + default: + return -EIO; + } +} + /* * Reads an shdlc frame from the chip. This is not as straightforward as it * seems. There are cases where we could loose the frame start synchronization. @@ -347,19 +448,23 @@ static irqreturn_t pn544_hci_i2c_irq_thread_fn(int irq, void *phy_id) if (phy->hard_fault != 0) return IRQ_HANDLED; - r = pn544_hci_i2c_read(phy, &skb); - if (r == -EREMOTEIO) { - phy->hard_fault = r; - - nfc_hci_recv_frame(phy->hdev, NULL); + if (phy->run_mode == PN544_FW_MODE) { + phy->fw_cmd_result = pn544_hci_i2c_fw_read_status(phy); + schedule_work(&phy->fw_work); + } else { + r = pn544_hci_i2c_read(phy, &skb); + if (r == -EREMOTEIO) { + phy->hard_fault = r; - return IRQ_HANDLED; - } else if ((r == -ENOMEM) || (r == -EBADMSG)) { - return IRQ_HANDLED; - } + nfc_hci_recv_frame(phy->hdev, NULL); - nfc_hci_recv_frame(phy->hdev, skb); + return IRQ_HANDLED; + } else if ((r == -ENOMEM) || (r == -EBADMSG)) { + return IRQ_HANDLED; + } + nfc_hci_recv_frame(phy->hdev, skb); + } return IRQ_HANDLED; } @@ -369,6 +474,215 @@ static struct nfc_phy_ops i2c_phy_ops = { .disable = pn544_hci_i2c_disable, }; +static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name) +{ + struct pn544_i2c_phy *phy = phy_id; + + pr_info(DRIVER_DESC ": Starting Firmware Download (%s)\n", + firmware_name); + + strcpy(phy->firmware_name, firmware_name); + + phy->fw_work_state = FW_WORK_STATE_START; + + schedule_work(&phy->fw_work); + + return 0; +} + +static void pn544_hci_i2c_fw_work_complete(struct pn544_i2c_phy *phy, + int result) +{ + pr_info(DRIVER_DESC ": Firmware Download Complete, result=%d\n", result); + + pn544_hci_i2c_disable(phy); + + phy->fw_work_state = FW_WORK_STATE_IDLE; + + if (phy->fw) { + release_firmware(phy->fw); + phy->fw = NULL; + } + + nfc_fw_download_done(phy->hdev->ndev, phy->firmware_name, (u32) -result); +} + +static int pn544_hci_i2c_fw_write_cmd(struct i2c_client *client, u32 dest_addr, + const u8 *data, u16 datalen) +{ + u8 frame[PN544_FW_I2C_MAX_PAYLOAD]; + struct pn544_i2c_fw_frame_write *framep; + u16 params_len; + int framelen; + int r; + + if (datalen > PN544_FW_I2C_WRITE_DATA_MAX_LEN) + datalen = PN544_FW_I2C_WRITE_DATA_MAX_LEN; + + framep = (struct pn544_i2c_fw_frame_write *) frame; + + params_len = sizeof(framep->be_dest_addr) + + sizeof(framep->be_datalen) + datalen; + framelen = params_len + sizeof(framep->cmd) + + sizeof(framep->be_length); + + framep->cmd = PN544_FW_CMD_WRITE; + + put_unaligned_be16(params_len, &framep->be_length); + + framep->be_dest_addr[0] = (dest_addr & 0xff0000) >> 16; + framep->be_dest_addr[1] = (dest_addr & 0xff00) >> 8; + framep->be_dest_addr[2] = dest_addr & 0xff; + + put_unaligned_be16(datalen, &framep->be_datalen); + + memcpy(framep->data, data, datalen); + + r = i2c_master_send(client, frame, framelen); + + if (r == framelen) + return datalen; + else if (r < 0) + return r; + else + return -EIO; +} + +static int pn544_hci_i2c_fw_check_cmd(struct i2c_client *client, u32 start_addr, + const u8 *data, u16 datalen) +{ + struct pn544_i2c_fw_frame_check frame; + int r; + u16 crc; + + /* calculate local crc for the data we want to check */ + crc = crc_ccitt(0xffff, data, datalen); + + frame.cmd = PN544_FW_CMD_CHECK; + + put_unaligned_be16(sizeof(frame.be_start_addr) + + sizeof(frame.be_datalen) + sizeof(frame.be_crc), + &frame.be_length); + + /* tell the chip the memory region to which our crc applies */ + frame.be_start_addr[0] = (start_addr & 0xff0000) >> 16; + frame.be_start_addr[1] = (start_addr & 0xff00) >> 8; + frame.be_start_addr[2] = start_addr & 0xff; + + put_unaligned_be16(datalen, &frame.be_datalen); + + /* + * and give our local crc. Chip will calculate its own crc for the + * region and compare with ours. + */ + put_unaligned_be16(crc, &frame.be_crc); + + r = i2c_master_send(client, (const char *) &frame, sizeof(frame)); + + if (r == sizeof(frame)) + return 0; + else if (r < 0) + return r; + else + return -EIO; +} + +static int pn544_hci_i2c_fw_write_chunk(struct pn544_i2c_phy *phy) +{ + int r; + + r = pn544_hci_i2c_fw_write_cmd(phy->i2c_dev, + phy->fw_blob_dest_addr + phy->fw_written, + phy->fw_blob_data + phy->fw_written, + phy->fw_blob_size - phy->fw_written); + if (r < 0) + return r; + + phy->fw_written += r; + phy->fw_work_state = FW_WORK_STATE_WAIT_WRITE_ANSWER; + + return 0; +} + +static void pn544_hci_i2c_fw_work(struct work_struct *work) +{ + struct pn544_i2c_phy *phy = container_of(work, struct pn544_i2c_phy, + fw_work); + int r; + struct pn544_i2c_fw_blob *blob; + + switch (phy->fw_work_state) { + case FW_WORK_STATE_START: + pn544_hci_i2c_enable_mode(phy, PN544_FW_MODE); + + r = request_firmware(&phy->fw, phy->firmware_name, + &phy->i2c_dev->dev); + if (r < 0) + goto exit_state_start; + + blob = (struct pn544_i2c_fw_blob *) phy->fw->data; + phy->fw_blob_size = get_unaligned_be32(&blob->be_size); + phy->fw_blob_dest_addr = get_unaligned_be32(&blob->be_destaddr); + phy->fw_blob_data = blob->data; + + phy->fw_written = 0; + r = pn544_hci_i2c_fw_write_chunk(phy); + +exit_state_start: + if (r < 0) + pn544_hci_i2c_fw_work_complete(phy, r); + break; + + case FW_WORK_STATE_WAIT_WRITE_ANSWER: + r = phy->fw_cmd_result; + if (r < 0) + goto exit_state_wait_write_answer; + + if (phy->fw_written == phy->fw_blob_size) { + r = pn544_hci_i2c_fw_check_cmd(phy->i2c_dev, + phy->fw_blob_dest_addr, + phy->fw_blob_data, + phy->fw_blob_size); + if (r < 0) + goto exit_state_wait_write_answer; + phy->fw_work_state = FW_WORK_STATE_WAIT_CHECK_ANSWER; + break; + } + + r = pn544_hci_i2c_fw_write_chunk(phy); + +exit_state_wait_write_answer: + if (r < 0) + pn544_hci_i2c_fw_work_complete(phy, r); + break; + + case FW_WORK_STATE_WAIT_CHECK_ANSWER: + r = phy->fw_cmd_result; + if (r < 0) + goto exit_state_wait_check_answer; + + blob = (struct pn544_i2c_fw_blob *) (phy->fw_blob_data + + phy->fw_blob_size); + phy->fw_blob_size = get_unaligned_be32(&blob->be_size); + if (phy->fw_blob_size != 0) { + phy->fw_blob_dest_addr = + get_unaligned_be32(&blob->be_destaddr); + phy->fw_blob_data = blob->data; + + phy->fw_written = 0; + r = pn544_hci_i2c_fw_write_chunk(phy); + } + +exit_state_wait_check_answer: + if (r < 0 || phy->fw_blob_size == 0) + pn544_hci_i2c_fw_work_complete(phy, r); + break; + + default: + break; + } +} + static int pn544_hci_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -392,6 +706,9 @@ static int pn544_hci_i2c_probe(struct i2c_client *client, return -ENOMEM; } + INIT_WORK(&phy->fw_work, pn544_hci_i2c_fw_work); + phy->fw_work_state = FW_WORK_STATE_IDLE; + phy->i2c_dev = client; i2c_set_clientdata(client, phy); @@ -428,7 +745,8 @@ static int pn544_hci_i2c_probe(struct i2c_client *client, r = pn544_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME, PN544_I2C_FRAME_HEADROOM, PN544_I2C_FRAME_TAILROOM, - PN544_HCI_I2C_LLC_MAX_PAYLOAD, NULL, &phy->hdev); + PN544_HCI_I2C_LLC_MAX_PAYLOAD, + pn544_hci_i2c_fw_download, &phy->hdev); if (r < 0) goto err_hci; @@ -451,6 +769,10 @@ static int pn544_hci_i2c_remove(struct i2c_client *client) dev_dbg(&client->dev, "%s\n", __func__); + cancel_work_sync(&phy->fw_work); + if (phy->fw_work_state != FW_WORK_STATE_IDLE) + pn544_hci_i2c_fw_work_complete(phy, -ENODEV); + pn544_hci_remove(phy->hdev); if (phy->powered) -- cgit v1.2.3-70-g09d2