From e997ebbe46fe46bd4e8d476adca1f9b76779f270 Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Fri, 25 Mar 2016 15:46:51 +0100 Subject: NFC: pn533: Send ATR_REQ only if NFC_PROTO_NFC_DEP bit is set Currently it is not possible to only poll for passive targets with the pn533 driver. To change this ATR_REQ is only sent when NFC_PROTO_NFC_DEP is explicitly requested in poll_protocols. As most implementations (e.g. neard) poll for all protocols that are reported to be supported by the adapter, this should not have much of an effect on current implementations. Signed-off-by: Michael Thalmeier Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index bb3d5ea9869c..a85830fcafd0 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1540,7 +1540,8 @@ static int pn533_start_poll_complete(struct pn533 *dev, struct sk_buff *resp) int rc, tgdata_len; /* Toggle the DEP polling */ - dev->poll_dep = 1; + if (dev->poll_protocols & NFC_PROTO_NFC_DEP_MASK) + dev->poll_dep = 1; nbtg = resp->data[0]; tg = resp->data[1]; @@ -2054,7 +2055,7 @@ static int pn533_send_poll_frame(struct pn533 *dev) dev_dbg(&dev->interface->dev, "%s mod len %d\n", __func__, mod->len); - if (dev->poll_dep) { + if ((dev->poll_protocols & NFC_PROTO_NFC_DEP_MASK) && dev->poll_dep) { dev->poll_dep = 0; return pn533_poll_dep(dev->nfc_dev); } -- cgit v1.2.3 From 37f895d7e85e7d7e23e2395e666ea43001862e5f Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Fri, 25 Mar 2016 15:46:52 +0100 Subject: NFC: pn533: Fix socket deadlock A deadlock can occur when the NFC raw socket is closed while the driver is processing a command. Following is the call graph of the affected situation: send data via raw_sock: ------------- rawsock_tx_work sock_hold => socket refcnt++ nfc_data_exchange => cb = rawsock_data_exchange_complete ops->im_transceive = pn533_transceive => arg->cb = db = rawsock_data_exchange_complete pn533_send_data_async => cb = pn533_data_exchange_complete __pn533_send_async => cmd->complete_cb = cb = pn533_data_exchange_complete if_ops->send_frame_async response: -------- pn533_recv_response queue_work(priv->wq, &priv->cmd_complete_work) pn533_wq_cmd_complete pn533_send_async_complete cmd->complete_cb() = pn533_data_exchange_complete() arg->cb() = rawsock_data_exchange_complete() sock_put => socket refcnt-- => If the corresponding socket gets closed in the meantime socket will be destructed sk_free __sk_free sk->sk_destruct = rawsock_destruct nfc_deactivate_target ops->deactivate_target = pn533_deactivate_target pn533_send_cmd_sync pn533_send_cmd_async __pn533_send_async list_add_tail(&cmd->queue,&dev->cmd_queue) => add to command list because a command is currently processed wait_for_completion => the workqueue thread waits here because it is the one processing the commands => deadlock To fix the deadlock pn533_deactivate_target is changed to issue the PN533_CMD_IN_RELEASE command in async mode. This way nothing blocks and the release command is executed after the current command. Signed-off-by: Michael Thalmeier Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index a85830fcafd0..074f1e42e378 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -2263,12 +2263,35 @@ static int pn533_activate_target(struct nfc_dev *nfc_dev, return 0; } +static int pn533_deactivate_target_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp) +{ + int rc = 0; + + dev_dbg(&dev->interface->dev, "%s\n", __func__); + + if (IS_ERR(resp)) { + rc = PTR_ERR(resp); + + nfc_err(&dev->interface->dev, "Target release error %d\n", rc); + + return rc; + } + + rc = resp->data[0] & PN533_CMD_RET_MASK; + if (rc != PN533_CMD_RET_SUCCESS) + nfc_err(&dev->interface->dev, + "Error 0x%x when releasing the target\n", rc); + + dev_kfree_skb(resp); + return rc; +} + static void pn533_deactivate_target(struct nfc_dev *nfc_dev, struct nfc_target *target, u8 mode) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); struct sk_buff *skb; - struct sk_buff *resp; int rc; dev_dbg(&dev->interface->dev, "%s\n", __func__); @@ -2287,16 +2310,13 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, *skb_put(skb, 1) = 1; /* TG*/ - resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_RELEASE, skb); - if (IS_ERR(resp)) - return; - - rc = resp->data[0] & PN533_CMD_RET_MASK; - if (rc != PN533_CMD_RET_SUCCESS) - nfc_err(&dev->interface->dev, - "Error 0x%x when releasing the target\n", rc); + rc = pn533_send_cmd_async(dev, PN533_CMD_IN_RELEASE, skb, + pn533_deactivate_target_complete, NULL); + if (rc < 0) { + dev_kfree_skb(skb); + nfc_err(&dev->interface->dev, "Target release error %d\n", rc); + } - dev_kfree_skb(resp); return; } -- cgit v1.2.3 From 9815c7cf22daceabfb919ddcd6f2c80e049c1fbc Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Fri, 25 Mar 2016 15:46:53 +0100 Subject: NFC: pn533: Separate physical layer from the core implementation The driver now has all core stuff isolated in one file, and all the hardware link specifics in another. Writing a pn533 driver on top of another hardware link is now just a matter of adding a new file for that new hardware specifics. The first user of this separation will be the i2c based pn532 driver that reuses pn533 core implementation on top of an i2c layer. Signed-off-by: Michael Thalmeier Signed-off-by: Samuel Ortiz --- drivers/nfc/Kconfig | 11 +- drivers/nfc/Makefile | 2 +- drivers/nfc/pn533.c | 3334 -------------------------------------------- drivers/nfc/pn533/Kconfig | 16 + drivers/nfc/pn533/Makefile | 7 + drivers/nfc/pn533/pn533.c | 2644 +++++++++++++++++++++++++++++++++++ drivers/nfc/pn533/pn533.h | 235 ++++ drivers/nfc/pn533/usb.c | 598 ++++++++ 8 files changed, 3502 insertions(+), 3345 deletions(-) delete mode 100644 drivers/nfc/pn533.c create mode 100644 drivers/nfc/pn533/Kconfig create mode 100644 drivers/nfc/pn533/Makefile create mode 100644 drivers/nfc/pn533/pn533.c create mode 100644 drivers/nfc/pn533/pn533.h create mode 100644 drivers/nfc/pn533/usb.c diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 7437c9dfd8fc..ea8321a483f9 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -5,16 +5,6 @@ menu "Near Field Communication (NFC) devices" depends on NFC -config NFC_PN533 - tristate "NXP PN533 USB driver" - depends on USB - help - NXP PN533 USB driver. - This driver provides support for NFC NXP PN533 devices. - - Say Y here to compile support for PN533 devices into the - kernel or say M to compile it as module (pn533). - config NFC_WILINK tristate "Texas Instruments NFC WiLink driver" depends on TI_ST && NFC_NCI @@ -70,6 +60,7 @@ config NFC_PORT100 source "drivers/nfc/fdp/Kconfig" source "drivers/nfc/pn544/Kconfig" +source "drivers/nfc/pn533/Kconfig" source "drivers/nfc/microread/Kconfig" source "drivers/nfc/nfcmrvl/Kconfig" source "drivers/nfc/st21nfca/Kconfig" diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 0a99e67daa10..bab8ef06ae35 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_NFC_FDP) += fdp/ obj-$(CONFIG_NFC_PN544) += pn544/ obj-$(CONFIG_NFC_MICROREAD) += microread/ -obj-$(CONFIG_NFC_PN533) += pn533.o +obj-$(CONFIG_NFC_PN533) += pn533/ obj-$(CONFIG_NFC_WILINK) += nfcwilink.o obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o obj-$(CONFIG_NFC_SIM) += nfcsim.o diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c deleted file mode 100644 index 074f1e42e378..000000000000 --- a/drivers/nfc/pn533.c +++ /dev/null @@ -1,3334 +0,0 @@ -/* - * Copyright (C) 2011 Instituto Nokia de Tecnologia - * Copyright (C) 2012-2013 Tieto Poland - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define VERSION "0.2" - -#define PN533_VENDOR_ID 0x4CC -#define PN533_PRODUCT_ID 0x2533 - -#define SCM_VENDOR_ID 0x4E6 -#define SCL3711_PRODUCT_ID 0x5591 - -#define SONY_VENDOR_ID 0x054c -#define PASORI_PRODUCT_ID 0x02e1 - -#define ACS_VENDOR_ID 0x072f -#define ACR122U_PRODUCT_ID 0x2200 - -#define PN533_DEVICE_STD 0x1 -#define PN533_DEVICE_PASORI 0x2 -#define PN533_DEVICE_ACR122U 0x3 - -#define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ - NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ - NFC_PROTO_NFC_DEP_MASK |\ - NFC_PROTO_ISO14443_B_MASK) - -#define PN533_NO_TYPE_B_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ - NFC_PROTO_MIFARE_MASK | \ - NFC_PROTO_FELICA_MASK | \ - NFC_PROTO_ISO14443_MASK | \ - NFC_PROTO_NFC_DEP_MASK) - -static const struct usb_device_id pn533_table[] = { - { USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID), - .driver_info = PN533_DEVICE_STD }, - { USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID), - .driver_info = PN533_DEVICE_STD }, - { USB_DEVICE(SONY_VENDOR_ID, PASORI_PRODUCT_ID), - .driver_info = PN533_DEVICE_PASORI }, - { USB_DEVICE(ACS_VENDOR_ID, ACR122U_PRODUCT_ID), - .driver_info = PN533_DEVICE_ACR122U }, - { } -}; -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) \ - + 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. - */ -#define PN533_STD_FRAME_MAX_PAYLOAD_LEN 263 - -#define PN533_STD_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2), - 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 - -/* standard frame identifier: in/out/error */ -#define PN533_STD_FRAME_IDENTIFIER(f) (f->data[0]) /* TFI */ -#define PN533_STD_FRAME_DIR_OUT 0xD4 -#define PN533_STD_FRAME_DIR_IN 0xD5 - -/* ACS ACR122 pn533 frame definitions */ -#define PN533_ACR122_TX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_tx_frame) \ - + 2) -#define PN533_ACR122_TX_FRAME_TAIL_LEN 0 -#define PN533_ACR122_RX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_rx_frame) \ - + 2) -#define PN533_ACR122_RX_FRAME_TAIL_LEN 2 -#define PN533_ACR122_FRAME_MAX_PAYLOAD_LEN PN533_STD_FRAME_MAX_PAYLOAD_LEN - -/* CCID messages types */ -#define PN533_ACR122_PC_TO_RDR_ICCPOWERON 0x62 -#define PN533_ACR122_PC_TO_RDR_ESCAPE 0x6B - -#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83 - -/* PN533 Commands */ -#define PN533_FRAME_CMD(f) (f->data[1]) - -#define PN533_CMD_GET_FIRMWARE_VERSION 0x02 -#define PN533_CMD_RF_CONFIGURATION 0x32 -#define PN533_CMD_IN_DATA_EXCHANGE 0x40 -#define PN533_CMD_IN_COMM_THRU 0x42 -#define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A -#define PN533_CMD_IN_ATR 0x50 -#define PN533_CMD_IN_RELEASE 0x52 -#define PN533_CMD_IN_JUMP_FOR_DEP 0x56 - -#define PN533_CMD_TG_INIT_AS_TARGET 0x8c -#define PN533_CMD_TG_GET_DATA 0x86 -#define PN533_CMD_TG_SET_DATA 0x8e -#define PN533_CMD_TG_SET_META_DATA 0x94 -#define PN533_CMD_UNDEF 0xff - -#define PN533_CMD_RESPONSE(cmd) (cmd + 1) - -/* PN533 Return codes */ -#define PN533_CMD_RET_MASK 0x3F -#define PN533_CMD_MI_MASK 0x40 -#define PN533_CMD_RET_SUCCESS 0x00 - -struct pn533; - -typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg, - struct sk_buff *resp); - -/* structs for pn533 commands */ - -/* PN533_CMD_GET_FIRMWARE_VERSION */ -struct pn533_fw_version { - u8 ic; - u8 ver; - u8 rev; - u8 support; -}; - -/* PN533_CMD_RF_CONFIGURATION */ -#define PN533_CFGITEM_RF_FIELD 0x01 -#define PN533_CFGITEM_TIMING 0x02 -#define PN533_CFGITEM_MAX_RETRIES 0x05 -#define PN533_CFGITEM_PASORI 0x82 - -#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 -#define PN533_CONFIG_TIMING_409 0xd -#define PN533_CONFIG_TIMING_819 0xe - -#define PN533_CONFIG_MAX_RETRIES_NO_RETRY 0x00 -#define PN533_CONFIG_MAX_RETRIES_ENDLESS 0xFF - -struct pn533_config_max_retries { - u8 mx_rty_atr; - u8 mx_rty_psl; - u8 mx_rty_passive_act; -} __packed; - -struct pn533_config_timing { - u8 rfu; - u8 atr_res_timeout; - u8 dep_timeout; -} __packed; - -/* PN533_CMD_IN_LIST_PASSIVE_TARGET */ - -/* felica commands opcode */ -#define PN533_FELICA_OPC_SENSF_REQ 0 -#define PN533_FELICA_OPC_SENSF_RES 1 -/* felica SENSF_REQ parameters */ -#define PN533_FELICA_SENSF_SC_ALL 0xFFFF -#define PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE 0 -#define PN533_FELICA_SENSF_RC_SYSTEM_CODE 1 -#define PN533_FELICA_SENSF_RC_ADVANCED_PROTOCOL 2 - -/* type B initiator_data values */ -#define PN533_TYPE_B_AFI_ALL_FAMILIES 0 -#define PN533_TYPE_B_POLL_METHOD_TIMESLOT 0 -#define PN533_TYPE_B_POLL_METHOD_PROBABILISTIC 1 - -union pn533_cmd_poll_initdata { - struct { - u8 afi; - u8 polling_method; - } __packed type_b; - struct { - u8 opcode; - __be16 sc; - u8 rc; - u8 tsn; - } __packed felica; -}; - -/* Poll modulations */ -enum { - PN533_POLL_MOD_106KBPS_A, - PN533_POLL_MOD_212KBPS_FELICA, - PN533_POLL_MOD_424KBPS_FELICA, - PN533_POLL_MOD_106KBPS_JEWEL, - PN533_POLL_MOD_847KBPS_B, - PN533_LISTEN_MOD, - - __PN533_POLL_MOD_AFTER_LAST, -}; -#define PN533_POLL_MOD_MAX (__PN533_POLL_MOD_AFTER_LAST - 1) - -struct pn533_poll_modulations { - struct { - u8 maxtg; - u8 brty; - union pn533_cmd_poll_initdata initiator_data; - } __packed data; - u8 len; -}; - -static const struct pn533_poll_modulations poll_mod[] = { - [PN533_POLL_MOD_106KBPS_A] = { - .data = { - .maxtg = 1, - .brty = 0, - }, - .len = 2, - }, - [PN533_POLL_MOD_212KBPS_FELICA] = { - .data = { - .maxtg = 1, - .brty = 1, - .initiator_data.felica = { - .opcode = PN533_FELICA_OPC_SENSF_REQ, - .sc = PN533_FELICA_SENSF_SC_ALL, - .rc = PN533_FELICA_SENSF_RC_SYSTEM_CODE, - .tsn = 0x03, - }, - }, - .len = 7, - }, - [PN533_POLL_MOD_424KBPS_FELICA] = { - .data = { - .maxtg = 1, - .brty = 2, - .initiator_data.felica = { - .opcode = PN533_FELICA_OPC_SENSF_REQ, - .sc = PN533_FELICA_SENSF_SC_ALL, - .rc = PN533_FELICA_SENSF_RC_SYSTEM_CODE, - .tsn = 0x03, - }, - }, - .len = 7, - }, - [PN533_POLL_MOD_106KBPS_JEWEL] = { - .data = { - .maxtg = 1, - .brty = 4, - }, - .len = 2, - }, - [PN533_POLL_MOD_847KBPS_B] = { - .data = { - .maxtg = 1, - .brty = 8, - .initiator_data.type_b = { - .afi = PN533_TYPE_B_AFI_ALL_FAMILIES, - .polling_method = - PN533_TYPE_B_POLL_METHOD_TIMESLOT, - }, - }, - .len = 3, - }, - [PN533_LISTEN_MOD] = { - .len = 0, - }, -}; - -/* PN533_CMD_IN_ATR */ - -struct pn533_cmd_activate_response { - u8 status; - u8 nfcid3t[10]; - u8 didt; - u8 bst; - u8 brt; - u8 to; - u8 ppt; - /* optional */ - u8 gt[]; -} __packed; - -struct pn533_cmd_jump_dep_response { - u8 status; - u8 tg; - u8 nfcid3t[10]; - u8 didt; - u8 bst; - u8 brt; - u8 to; - u8 ppt; - /* optional */ - u8 gt[]; -} __packed; - - -/* PN533_TG_INIT_AS_TARGET */ -#define PN533_INIT_TARGET_PASSIVE 0x1 -#define PN533_INIT_TARGET_DEP 0x2 - -#define PN533_INIT_TARGET_RESP_FRAME_MASK 0x3 -#define PN533_INIT_TARGET_RESP_ACTIVE 0x1 -#define PN533_INIT_TARGET_RESP_DEP 0x4 - -enum pn533_protocol_type { - PN533_PROTO_REQ_ACK_RESP = 0, - PN533_PROTO_REQ_RESP -}; - -struct pn533 { - struct usb_device *udev; - struct usb_interface *interface; - struct nfc_dev *nfc_dev; - u32 device_type; - enum pn533_protocol_type protocol_type; - - struct urb *out_urb; - 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 delayed_work poll_work; - struct work_struct mi_rx_work; - struct work_struct mi_tx_work; - struct work_struct mi_tm_rx_work; - struct work_struct mi_tm_tx_work; - struct work_struct tg_work; - struct work_struct rf_work; - - struct list_head cmd_queue; - struct pn533_cmd *cmd; - u8 cmd_pending; - 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; - u8 poll_mod_curr; - u8 poll_dep; - u32 poll_protocols; - u32 listen_protocols; - struct timer_list listen_timer; - int cancel_listen; - - u8 *gb; - size_t gb_len; - - u8 tgt_available_prots; - u8 tgt_active_prot; - u8 tgt_mode; - - struct pn533_frame_ops *ops; -}; - -struct pn533_cmd { - struct list_head queue; - u8 code; - int status; - struct sk_buff *req; - struct sk_buff *resp; - int resp_len; - pn533_send_async_complete_t complete_cb; - void *complete_cb_context; -}; - -struct pn533_std_frame { - u8 preamble; - __be16 start_frame; - u8 datalen; - u8 datalen_checksum; - 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); - void (*tx_update_payload_len)(void *frame, int len); - int tx_header_len; - int tx_tail_len; - - bool (*rx_is_frame_valid)(void *frame, struct pn533 *dev); - int (*rx_frame_size)(void *frame); - int rx_header_len; - int rx_tail_len; - - int max_payload_len; - u8 (*get_cmd_code)(void *frame); -}; - -struct pn533_acr122_ccid_hdr { - u8 type; - u32 datalen; - u8 slot; - u8 seq; - u8 params[3]; /* 3 msg specific bytes or status, error and 1 specific - byte for reposnse msg */ - u8 data[]; /* payload */ -} __packed; - -struct pn533_acr122_apdu_hdr { - u8 class; - u8 ins; - u8 p1; - u8 p2; -} __packed; - -struct pn533_acr122_tx_frame { - struct pn533_acr122_ccid_hdr ccid; - struct pn533_acr122_apdu_hdr apdu; - u8 datalen; - u8 data[]; /* pn533 frame: TFI ... */ -} __packed; - -struct pn533_acr122_rx_frame { - struct pn533_acr122_ccid_hdr ccid; - u8 data[]; /* pn533 frame : TFI ... */ -} __packed; - -static void pn533_acr122_tx_frame_init(void *_frame, u8 cmd_code) -{ - struct pn533_acr122_tx_frame *frame = _frame; - - frame->ccid.type = PN533_ACR122_PC_TO_RDR_ESCAPE; - frame->ccid.datalen = sizeof(frame->apdu) + 1; /* sizeof(apdu_hdr) + - sizeof(datalen) */ - frame->ccid.slot = 0; - frame->ccid.seq = 0; - frame->ccid.params[0] = 0; - frame->ccid.params[1] = 0; - frame->ccid.params[2] = 0; - - frame->data[0] = PN533_STD_FRAME_DIR_OUT; - frame->data[1] = cmd_code; - frame->datalen = 2; /* data[0] + data[1] */ - - frame->apdu.class = 0xFF; - frame->apdu.ins = 0; - frame->apdu.p1 = 0; - frame->apdu.p2 = 0; -} - -static void pn533_acr122_tx_frame_finish(void *_frame) -{ - struct pn533_acr122_tx_frame *frame = _frame; - - frame->ccid.datalen += frame->datalen; -} - -static void pn533_acr122_tx_update_payload_len(void *_frame, int len) -{ - struct pn533_acr122_tx_frame *frame = _frame; - - frame->datalen += len; -} - -static bool pn533_acr122_is_rx_frame_valid(void *_frame, struct pn533 *dev) -{ - struct pn533_acr122_rx_frame *frame = _frame; - - if (frame->ccid.type != 0x83) - return false; - - if (!frame->ccid.datalen) - return false; - - if (frame->data[frame->ccid.datalen - 2] == 0x63) - return false; - - return true; -} - -static int pn533_acr122_rx_frame_size(void *frame) -{ - struct pn533_acr122_rx_frame *f = frame; - - /* f->ccid.datalen already includes tail length */ - return sizeof(struct pn533_acr122_rx_frame) + f->ccid.datalen; -} - -static u8 pn533_acr122_get_cmd_code(void *frame) -{ - struct pn533_acr122_rx_frame *f = frame; - - return PN533_FRAME_CMD(f); -} - -static struct pn533_frame_ops pn533_acr122_frame_ops = { - .tx_frame_init = pn533_acr122_tx_frame_init, - .tx_frame_finish = pn533_acr122_tx_frame_finish, - .tx_update_payload_len = pn533_acr122_tx_update_payload_len, - .tx_header_len = PN533_ACR122_TX_FRAME_HEADER_LEN, - .tx_tail_len = PN533_ACR122_TX_FRAME_TAIL_LEN, - - .rx_is_frame_valid = pn533_acr122_is_rx_frame_valid, - .rx_header_len = PN533_ACR122_RX_FRAME_HEADER_LEN, - .rx_tail_len = PN533_ACR122_RX_FRAME_TAIL_LEN, - .rx_frame_size = pn533_acr122_rx_frame_size, - - .max_payload_len = PN533_ACR122_FRAME_MAX_PAYLOAD_LEN, - .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) -{ - return ~value + 1; -} - -/* The rule: sum(data elements) + checksum = 0 */ -static u8 pn533_std_data_checksum(u8 *data, int datalen) -{ - u8 sum = 0; - int i; - - for (i = 0; i < datalen; i++) - sum += data[i]; - - return pn533_std_checksum(sum); -} - -static void pn533_std_tx_frame_init(void *_frame, u8 cmd_code) -{ - struct pn533_std_frame *frame = _frame; - - frame->preamble = 0; - frame->start_frame = cpu_to_be16(PN533_STD_FRAME_SOF); - PN533_STD_FRAME_IDENTIFIER(frame) = PN533_STD_FRAME_DIR_OUT; - PN533_FRAME_CMD(frame) = cmd_code; - frame->datalen = 2; -} - -static void pn533_std_tx_frame_finish(void *_frame) -{ - struct pn533_std_frame *frame = _frame; - - frame->datalen_checksum = pn533_std_checksum(frame->datalen); - - PN533_STD_FRAME_CHECKSUM(frame) = - pn533_std_data_checksum(frame->data, frame->datalen); - - PN533_STD_FRAME_POSTAMBLE(frame) = 0; -} - -static void pn533_std_tx_update_payload_len(void *_frame, int len) -{ - struct pn533_std_frame *frame = _frame; - - frame->datalen += len; -} - -static bool pn533_std_rx_frame_is_valid(void *_frame, struct pn533 *dev) -{ - u8 checksum; - struct pn533_std_frame *stdf = _frame; - - if (stdf->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF)) - return false; - - 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) - 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; - - 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; - - /* 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; -} - -static bool pn533_std_rx_frame_is_ack(struct pn533_std_frame *frame) -{ - if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF)) - return false; - - if (frame->datalen != 0 || frame->datalen_checksum != 0xFF) - return false; - - return true; -} - -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; -} - -static u8 pn533_std_get_cmd_code(void *frame) -{ - struct pn533_std_frame *f = frame; - struct pn533_ext_frame *eif = frame; - - 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 = { - .tx_frame_init = pn533_std_tx_frame_init, - .tx_frame_finish = pn533_std_tx_frame_finish, - .tx_update_payload_len = pn533_std_tx_update_payload_len, - .tx_header_len = PN533_STD_FRAME_HEADER_LEN, - .tx_tail_len = PN533_STD_FRAME_TAIL_LEN, - - .rx_is_frame_valid = pn533_std_rx_frame_is_valid, - .rx_frame_size = pn533_std_rx_frame_size, - .rx_header_len = PN533_STD_FRAME_HEADER_LEN, - .rx_tail_len = PN533_STD_FRAME_TAIL_LEN, - - .max_payload_len = PN533_STD_FRAME_MAX_PAYLOAD_LEN, - .get_cmd_code = pn533_std_get_cmd_code, -}; - -static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame) -{ - return (dev->ops->get_cmd_code(frame) == - PN533_CMD_RESPONSE(dev->cmd->code)); -} - -static void pn533_recv_response(struct urb *urb) -{ - struct pn533 *dev = urb->context; - struct pn533_cmd *cmd = dev->cmd; - u8 *in_frame; - - cmd->status = urb->status; - - switch (urb->status) { - case 0: - break; /* success */ - case -ECONNRESET: - case -ENOENT: - dev_dbg(&dev->interface->dev, - "The urb has been canceled (status %d)\n", - urb->status); - goto sched_wq; - case -ESHUTDOWN: - default: - nfc_err(&dev->interface->dev, - "Urb failure (status %d)\n", urb->status); - goto sched_wq; - } - - in_frame = dev->in_urb->transfer_buffer; - - dev_dbg(&dev->interface->dev, "Received a frame\n"); - 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, dev)) { - nfc_err(&dev->interface->dev, "Received an invalid frame\n"); - cmd->status = -EIO; - goto sched_wq; - } - - if (!pn533_rx_frame_is_cmd_response(dev, in_frame)) { - nfc_err(&dev->interface->dev, - "It it not the response to the last command\n"); - cmd->status = -EIO; - goto sched_wq; - } - -sched_wq: - queue_work(dev->wq, &dev->cmd_complete_work); -} - -static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) -{ - dev->in_urb->complete = pn533_recv_response; - - return usb_submit_urb(dev->in_urb, flags); -} - -static void pn533_recv_ack(struct urb *urb) -{ - struct pn533 *dev = urb->context; - struct pn533_cmd *cmd = dev->cmd; - struct pn533_std_frame *in_frame; - int rc; - - cmd->status = urb->status; - - switch (urb->status) { - case 0: - break; /* success */ - case -ECONNRESET: - case -ENOENT: - dev_dbg(&dev->interface->dev, - "The urb has been stopped (status %d)\n", - urb->status); - goto sched_wq; - case -ESHUTDOWN: - default: - nfc_err(&dev->interface->dev, - "Urb failure (status %d)\n", urb->status); - goto sched_wq; - } - - in_frame = dev->in_urb->transfer_buffer; - - if (!pn533_std_rx_frame_is_ack(in_frame)) { - nfc_err(&dev->interface->dev, "Received an invalid ack\n"); - cmd->status = -EIO; - goto sched_wq; - } - - rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC); - if (rc) { - nfc_err(&dev->interface->dev, - "usb_submit_urb failed with result %d\n", rc); - cmd->status = rc; - goto sched_wq; - } - - return; - -sched_wq: - queue_work(dev->wq, &dev->cmd_complete_work); -} - -static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) -{ - dev->in_urb->complete = pn533_recv_ack; - - return usb_submit_urb(dev->in_urb, flags); -} - -static int pn533_send_ack(struct pn533 *dev, gfp_t flags) -{ - u8 ack[PN533_STD_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; - /* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */ - int rc; - - dev->out_urb->transfer_buffer = ack; - dev->out_urb->transfer_buffer_length = sizeof(ack); - rc = usb_submit_urb(dev->out_urb, flags); - - return rc; -} - -static int __pn533_send_frame_async(struct pn533 *dev, - struct sk_buff *out, - struct sk_buff *in, - int in_len) -{ - int rc; - - dev->out_urb->transfer_buffer = out->data; - dev->out_urb->transfer_buffer_length = out->len; - - dev->in_urb->transfer_buffer = in->data; - dev->in_urb->transfer_buffer_length = in_len; - - print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1, - out->data, out->len, false); - - rc = usb_submit_urb(dev->out_urb, GFP_KERNEL); - if (rc) - return rc; - - if (dev->protocol_type == PN533_PROTO_REQ_RESP) { - /* request for response for sent packet directly */ - rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC); - if (rc) - goto error; - } else if (dev->protocol_type == PN533_PROTO_REQ_ACK_RESP) { - /* request for ACK if that's the case */ - rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL); - if (rc) - goto error; - } - - return 0; - -error: - usb_unlink_urb(dev->out_urb); - return rc; -} - -static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code, - struct sk_buff *skb) -{ - /* payload is already there, just update datalen */ - int payload_len = skb->len; - struct pn533_frame_ops *ops = dev->ops; - - - skb_push(skb, ops->tx_header_len); - skb_put(skb, ops->tx_tail_len); - - ops->tx_frame_init(skb->data, cmd_code); - ops->tx_update_payload_len(skb->data, payload_len); - ops->tx_frame_finish(skb->data); -} - -static int pn533_send_async_complete(struct pn533 *dev) -{ - struct pn533_cmd *cmd = dev->cmd; - int status = cmd->status; - - struct sk_buff *req = cmd->req; - struct sk_buff *resp = cmd->resp; - - int rc; - - dev_kfree_skb(req); - - if (status < 0) { - rc = cmd->complete_cb(dev, cmd->complete_cb_context, - ERR_PTR(status)); - dev_kfree_skb(resp); - goto done; - } - - skb_put(resp, dev->ops->rx_frame_size(resp->data)); - skb_pull(resp, dev->ops->rx_header_len); - skb_trim(resp, resp->len - dev->ops->rx_tail_len); - - rc = cmd->complete_cb(dev, cmd->complete_cb_context, resp); - -done: - kfree(cmd); - dev->cmd = NULL; - return rc; -} - -static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, - struct sk_buff *req, struct sk_buff *resp, - int resp_len, - pn533_send_async_complete_t complete_cb, - void *complete_cb_context) -{ - struct pn533_cmd *cmd; - int rc = 0; - - dev_dbg(&dev->interface->dev, "Sending command 0x%x\n", cmd_code); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - cmd->code = cmd_code; - cmd->req = req; - cmd->resp = resp; - cmd->resp_len = resp_len; - cmd->complete_cb = complete_cb; - cmd->complete_cb_context = complete_cb_context; - - pn533_build_cmd_frame(dev, cmd_code, req); - - mutex_lock(&dev->cmd_lock); - - if (!dev->cmd_pending) { - rc = __pn533_send_frame_async(dev, req, resp, resp_len); - if (rc) - goto error; - - dev->cmd_pending = 1; - dev->cmd = cmd; - goto unlock; - } - - dev_dbg(&dev->interface->dev, "%s Queueing command 0x%x\n", - __func__, cmd_code); - - INIT_LIST_HEAD(&cmd->queue); - list_add_tail(&cmd->queue, &dev->cmd_queue); - - goto unlock; - -error: - kfree(cmd); -unlock: - mutex_unlock(&dev->cmd_lock); - return rc; -} - -static int pn533_send_data_async(struct pn533 *dev, u8 cmd_code, - struct sk_buff *req, - pn533_send_async_complete_t complete_cb, - void *complete_cb_context) -{ - struct sk_buff *resp; - int rc; - int resp_len = dev->ops->rx_header_len + - dev->ops->max_payload_len + - dev->ops->rx_tail_len; - - resp = nfc_alloc_recv_skb(resp_len, GFP_KERNEL); - if (!resp) - return -ENOMEM; - - rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb, - complete_cb_context); - if (rc) - dev_kfree_skb(resp); - - return rc; -} - -static int pn533_send_cmd_async(struct pn533 *dev, u8 cmd_code, - struct sk_buff *req, - pn533_send_async_complete_t complete_cb, - void *complete_cb_context) -{ - struct sk_buff *resp; - int rc; - int resp_len = dev->ops->rx_header_len + - dev->ops->max_payload_len + - dev->ops->rx_tail_len; - - resp = alloc_skb(resp_len, GFP_KERNEL); - if (!resp) - return -ENOMEM; - - rc = __pn533_send_async(dev, cmd_code, req, resp, resp_len, complete_cb, - complete_cb_context); - if (rc) - dev_kfree_skb(resp); - - return rc; -} - -/* - * pn533_send_cmd_direct_async - * - * The function sends a piority cmd directly to the chip omiting the cmd - * queue. It's intended to be used by chaining mechanism of received responses - * where the host has to request every single chunk of data before scheduling - * next cmd from the queue. - */ -static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, - struct sk_buff *req, - pn533_send_async_complete_t complete_cb, - void *complete_cb_context) -{ - struct sk_buff *resp; - struct pn533_cmd *cmd; - int rc; - int resp_len = dev->ops->rx_header_len + - dev->ops->max_payload_len + - dev->ops->rx_tail_len; - - resp = alloc_skb(resp_len, GFP_KERNEL); - if (!resp) - return -ENOMEM; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - dev_kfree_skb(resp); - return -ENOMEM; - } - - cmd->code = cmd_code; - cmd->req = req; - cmd->resp = resp; - cmd->resp_len = resp_len; - cmd->complete_cb = complete_cb; - cmd->complete_cb_context = complete_cb_context; - - pn533_build_cmd_frame(dev, cmd_code, req); - - rc = __pn533_send_frame_async(dev, req, resp, resp_len); - if (rc < 0) { - dev_kfree_skb(resp); - kfree(cmd); - } else { - dev->cmd = cmd; - } - - return rc; -} - -static void pn533_wq_cmd_complete(struct work_struct *work) -{ - struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work); - int rc; - - rc = pn533_send_async_complete(dev); - if (rc != -EINPROGRESS) - queue_work(dev->wq, &dev->cmd_work); -} - -static void pn533_wq_cmd(struct work_struct *work) -{ - struct pn533 *dev = container_of(work, struct pn533, cmd_work); - struct pn533_cmd *cmd; - int rc; - - mutex_lock(&dev->cmd_lock); - - if (list_empty(&dev->cmd_queue)) { - dev->cmd_pending = 0; - mutex_unlock(&dev->cmd_lock); - return; - } - - cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); - - list_del(&cmd->queue); - - mutex_unlock(&dev->cmd_lock); - - rc = __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len); - if (rc < 0) { - dev_kfree_skb(cmd->req); - dev_kfree_skb(cmd->resp); - kfree(cmd); - return; - } - - dev->cmd = cmd; -} - -struct pn533_sync_cmd_response { - struct sk_buff *resp; - struct completion done; -}; - -static int pn533_send_sync_complete(struct pn533 *dev, void *_arg, - struct sk_buff *resp) -{ - struct pn533_sync_cmd_response *arg = _arg; - - arg->resp = resp; - complete(&arg->done); - - return 0; -} - -/* pn533_send_cmd_sync - * - * Please note the req parameter is freed inside the function to - * limit a number of return value interpretations by the caller. - * - * 1. negative in case of error during TX path -> req should be freed - * - * 2. negative in case of error during RX path -> req should not be freed - * as it's been already freed at the begining of RX path by - * async_complete_cb. - * - * 3. valid pointer in case of succesfult RX path - * - * A caller has to check a return value with IS_ERR macro. If the test pass, - * the returned pointer is valid. - * - * */ -static struct sk_buff *pn533_send_cmd_sync(struct pn533 *dev, u8 cmd_code, - struct sk_buff *req) -{ - int rc; - struct pn533_sync_cmd_response arg; - - init_completion(&arg.done); - - rc = pn533_send_cmd_async(dev, cmd_code, req, - pn533_send_sync_complete, &arg); - if (rc) { - dev_kfree_skb(req); - return ERR_PTR(rc); - } - - wait_for_completion(&arg.done); - - return arg.resp; -} - -static void pn533_send_complete(struct urb *urb) -{ - struct pn533 *dev = urb->context; - - switch (urb->status) { - case 0: - break; /* success */ - case -ECONNRESET: - case -ENOENT: - dev_dbg(&dev->interface->dev, - "The urb has been stopped (status %d)\n", - urb->status); - break; - case -ESHUTDOWN: - default: - nfc_err(&dev->interface->dev, "Urb failure (status %d)\n", - urb->status); - } -} - -static void pn533_abort_cmd(struct pn533 *dev, gfp_t flags) -{ - /* ACR122U does not support any command which aborts last - * issued command i.e. as ACK for standard PN533. Additionally, - * it behaves stange, sending broken or incorrect responses, - * when we cancel urb before the chip will send response. - */ - if (dev->device_type == PN533_DEVICE_ACR122U) - return; - - /* An ack will cancel the last issued command */ - pn533_send_ack(dev, flags); - - /* cancel the urb request */ - usb_kill_urb(dev->in_urb); -} - -static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size) -{ - struct sk_buff *skb; - - skb = alloc_skb(dev->ops->tx_header_len + - size + - dev->ops->tx_tail_len, GFP_KERNEL); - - if (skb) - skb_reserve(skb, dev->ops->tx_header_len); - - return skb; -} - -struct pn533_target_type_a { - __be16 sens_res; - u8 sel_res; - u8 nfcid_len; - u8 nfcid_data[]; -} __packed; - - -#define PN533_TYPE_A_SENS_RES_NFCID1(x) ((u8)((be16_to_cpu(x) & 0x00C0) >> 6)) -#define PN533_TYPE_A_SENS_RES_SSD(x) ((u8)((be16_to_cpu(x) & 0x001F) >> 0)) -#define PN533_TYPE_A_SENS_RES_PLATCONF(x) ((u8)((be16_to_cpu(x) & 0x0F00) >> 8)) - -#define PN533_TYPE_A_SENS_RES_SSD_JEWEL 0x00 -#define PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL 0x0C - -#define PN533_TYPE_A_SEL_PROT(x) (((x) & 0x60) >> 5) -#define PN533_TYPE_A_SEL_CASCADE(x) (((x) & 0x04) >> 2) - -#define PN533_TYPE_A_SEL_PROT_MIFARE 0 -#define PN533_TYPE_A_SEL_PROT_ISO14443 1 -#define PN533_TYPE_A_SEL_PROT_DEP 2 -#define PN533_TYPE_A_SEL_PROT_ISO14443_DEP 3 - -static bool pn533_target_type_a_is_valid(struct pn533_target_type_a *type_a, - int target_data_len) -{ - u8 ssd; - u8 platconf; - - if (target_data_len < sizeof(struct pn533_target_type_a)) - return false; - - /* The lenght check of nfcid[] and ats[] are not being performed because - the values are not being used */ - - /* Requirement 4.6.3.3 from NFC Forum Digital Spec */ - ssd = PN533_TYPE_A_SENS_RES_SSD(type_a->sens_res); - platconf = PN533_TYPE_A_SENS_RES_PLATCONF(type_a->sens_res); - - if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL && - platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) || - (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL && - platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL)) - return false; - - /* Requirements 4.8.2.1, 4.8.2.3, 4.8.2.5 and 4.8.2.7 from NFC Forum */ - if (PN533_TYPE_A_SEL_CASCADE(type_a->sel_res) != 0) - return false; - - return true; -} - -static int pn533_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data, - int tgt_data_len) -{ - struct pn533_target_type_a *tgt_type_a; - - tgt_type_a = (struct pn533_target_type_a *)tgt_data; - - if (!pn533_target_type_a_is_valid(tgt_type_a, tgt_data_len)) - return -EPROTO; - - switch (PN533_TYPE_A_SEL_PROT(tgt_type_a->sel_res)) { - case PN533_TYPE_A_SEL_PROT_MIFARE: - nfc_tgt->supported_protocols = NFC_PROTO_MIFARE_MASK; - break; - case PN533_TYPE_A_SEL_PROT_ISO14443: - nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK; - break; - case PN533_TYPE_A_SEL_PROT_DEP: - nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK; - break; - case PN533_TYPE_A_SEL_PROT_ISO14443_DEP: - nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK | - NFC_PROTO_NFC_DEP_MASK; - break; - } - - nfc_tgt->sens_res = be16_to_cpu(tgt_type_a->sens_res); - nfc_tgt->sel_res = tgt_type_a->sel_res; - nfc_tgt->nfcid1_len = tgt_type_a->nfcid_len; - memcpy(nfc_tgt->nfcid1, tgt_type_a->nfcid_data, nfc_tgt->nfcid1_len); - - return 0; -} - -struct pn533_target_felica { - u8 pol_res; - u8 opcode; - u8 nfcid2[NFC_NFCID2_MAXSIZE]; - u8 pad[8]; - /* optional */ - u8 syst_code[]; -} __packed; - -#define PN533_FELICA_SENSF_NFCID2_DEP_B1 0x01 -#define PN533_FELICA_SENSF_NFCID2_DEP_B2 0xFE - -static bool pn533_target_felica_is_valid(struct pn533_target_felica *felica, - int target_data_len) -{ - if (target_data_len < sizeof(struct pn533_target_felica)) - return false; - - if (felica->opcode != PN533_FELICA_OPC_SENSF_RES) - return false; - - return true; -} - -static int pn533_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data, - int tgt_data_len) -{ - struct pn533_target_felica *tgt_felica; - - tgt_felica = (struct pn533_target_felica *)tgt_data; - - if (!pn533_target_felica_is_valid(tgt_felica, tgt_data_len)) - return -EPROTO; - - if ((tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1) && - (tgt_felica->nfcid2[1] == PN533_FELICA_SENSF_NFCID2_DEP_B2)) - nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK; - else - nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK; - - memcpy(nfc_tgt->sensf_res, &tgt_felica->opcode, 9); - nfc_tgt->sensf_res_len = 9; - - memcpy(nfc_tgt->nfcid2, tgt_felica->nfcid2, NFC_NFCID2_MAXSIZE); - nfc_tgt->nfcid2_len = NFC_NFCID2_MAXSIZE; - - return 0; -} - -struct pn533_target_jewel { - __be16 sens_res; - u8 jewelid[4]; -} __packed; - -static bool pn533_target_jewel_is_valid(struct pn533_target_jewel *jewel, - int target_data_len) -{ - u8 ssd; - u8 platconf; - - if (target_data_len < sizeof(struct pn533_target_jewel)) - return false; - - /* Requirement 4.6.3.3 from NFC Forum Digital Spec */ - ssd = PN533_TYPE_A_SENS_RES_SSD(jewel->sens_res); - platconf = PN533_TYPE_A_SENS_RES_PLATCONF(jewel->sens_res); - - if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL && - platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) || - (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL && - platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL)) - return false; - - return true; -} - -static int pn533_target_found_jewel(struct nfc_target *nfc_tgt, u8 *tgt_data, - int tgt_data_len) -{ - struct pn533_target_jewel *tgt_jewel; - - tgt_jewel = (struct pn533_target_jewel *)tgt_data; - - if (!pn533_target_jewel_is_valid(tgt_jewel, tgt_data_len)) - return -EPROTO; - - nfc_tgt->supported_protocols = NFC_PROTO_JEWEL_MASK; - nfc_tgt->sens_res = be16_to_cpu(tgt_jewel->sens_res); - nfc_tgt->nfcid1_len = 4; - memcpy(nfc_tgt->nfcid1, tgt_jewel->jewelid, nfc_tgt->nfcid1_len); - - return 0; -} - -struct pn533_type_b_prot_info { - u8 bitrate; - u8 fsci_type; - u8 fwi_adc_fo; -} __packed; - -#define PN533_TYPE_B_PROT_FCSI(x) (((x) & 0xF0) >> 4) -#define PN533_TYPE_B_PROT_TYPE(x) (((x) & 0x0F) >> 0) -#define PN533_TYPE_B_PROT_TYPE_RFU_MASK 0x8 - -struct pn533_type_b_sens_res { - u8 opcode; - u8 nfcid[4]; - u8 appdata[4]; - struct pn533_type_b_prot_info prot_info; -} __packed; - -#define PN533_TYPE_B_OPC_SENSB_RES 0x50 - -struct pn533_target_type_b { - struct pn533_type_b_sens_res sensb_res; - u8 attrib_res_len; - u8 attrib_res[]; -} __packed; - -static bool pn533_target_type_b_is_valid(struct pn533_target_type_b *type_b, - int target_data_len) -{ - if (target_data_len < sizeof(struct pn533_target_type_b)) - return false; - - if (type_b->sensb_res.opcode != PN533_TYPE_B_OPC_SENSB_RES) - return false; - - if (PN533_TYPE_B_PROT_TYPE(type_b->sensb_res.prot_info.fsci_type) & - PN533_TYPE_B_PROT_TYPE_RFU_MASK) - return false; - - return true; -} - -static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data, - int tgt_data_len) -{ - struct pn533_target_type_b *tgt_type_b; - - tgt_type_b = (struct pn533_target_type_b *)tgt_data; - - if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len)) - return -EPROTO; - - nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_B_MASK; - - return 0; -} - -static int pn533_target_found(struct pn533 *dev, u8 tg, u8 *tgdata, - int tgdata_len) -{ - struct nfc_target nfc_tgt; - int rc; - - dev_dbg(&dev->interface->dev, "%s: modulation=%d\n", - __func__, dev->poll_mod_curr); - - if (tg != 1) - return -EPROTO; - - memset(&nfc_tgt, 0, sizeof(struct nfc_target)); - - switch (dev->poll_mod_curr) { - case PN533_POLL_MOD_106KBPS_A: - rc = pn533_target_found_type_a(&nfc_tgt, tgdata, tgdata_len); - break; - case PN533_POLL_MOD_212KBPS_FELICA: - case PN533_POLL_MOD_424KBPS_FELICA: - rc = pn533_target_found_felica(&nfc_tgt, tgdata, tgdata_len); - break; - case PN533_POLL_MOD_106KBPS_JEWEL: - rc = pn533_target_found_jewel(&nfc_tgt, tgdata, tgdata_len); - break; - case PN533_POLL_MOD_847KBPS_B: - rc = pn533_target_found_type_b(&nfc_tgt, tgdata, tgdata_len); - break; - default: - nfc_err(&dev->interface->dev, - "Unknown current poll modulation\n"); - return -EPROTO; - } - - if (rc) - return rc; - - if (!(nfc_tgt.supported_protocols & dev->poll_protocols)) { - dev_dbg(&dev->interface->dev, - "The Tg found doesn't have the desired protocol\n"); - return -EAGAIN; - } - - dev_dbg(&dev->interface->dev, - "Target found - supported protocols: 0x%x\n", - nfc_tgt.supported_protocols); - - dev->tgt_available_prots = nfc_tgt.supported_protocols; - - nfc_targets_found(dev->nfc_dev, &nfc_tgt, 1); - - return 0; -} - -static inline void pn533_poll_next_mod(struct pn533 *dev) -{ - dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count; -} - -static void pn533_poll_reset_mod_list(struct pn533 *dev) -{ - dev->poll_mod_count = 0; -} - -static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index) -{ - dev->poll_mod_active[dev->poll_mod_count] = - (struct pn533_poll_modulations *)&poll_mod[mod_index]; - dev->poll_mod_count++; -} - -static void pn533_poll_create_mod_list(struct pn533 *dev, - u32 im_protocols, u32 tm_protocols) -{ - pn533_poll_reset_mod_list(dev); - - if ((im_protocols & NFC_PROTO_MIFARE_MASK) || - (im_protocols & NFC_PROTO_ISO14443_MASK) || - (im_protocols & NFC_PROTO_NFC_DEP_MASK)) - pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A); - - if (im_protocols & NFC_PROTO_FELICA_MASK || - im_protocols & NFC_PROTO_NFC_DEP_MASK) { - pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA); - pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA); - } - - if (im_protocols & NFC_PROTO_JEWEL_MASK) - pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL); - - if (im_protocols & NFC_PROTO_ISO14443_B_MASK) - pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B); - - if (tm_protocols) - pn533_poll_add_mod(dev, PN533_LISTEN_MOD); -} - -static int pn533_start_poll_complete(struct pn533 *dev, struct sk_buff *resp) -{ - u8 nbtg, tg, *tgdata; - int rc, tgdata_len; - - /* Toggle the DEP polling */ - if (dev->poll_protocols & NFC_PROTO_NFC_DEP_MASK) - dev->poll_dep = 1; - - nbtg = resp->data[0]; - tg = resp->data[1]; - tgdata = &resp->data[2]; - tgdata_len = resp->len - 2; /* nbtg + tg */ - - if (nbtg) { - rc = pn533_target_found(dev, tg, tgdata, tgdata_len); - - /* We must stop the poll after a valid target found */ - if (rc == 0) { - pn533_poll_reset_mod_list(dev); - return 0; - } - } - - return -EAGAIN; -} - -static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) -{ - struct sk_buff *skb; - u8 *felica, *nfcid3, *gb; - - u8 *gbytes = dev->gb; - size_t gbytes_len = dev->gb_len; - - u8 felica_params[18] = {0x1, 0xfe, /* DEP */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff}; /* System code */ - - u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */ - 0x0, 0x0, 0x0, - 0x40}; /* SEL_RES for DEP */ - - unsigned int skb_len = 36 + /* mode (1), mifare (6), - felica (18), nfcid3 (10), gb_len (1) */ - gbytes_len + - 1; /* len Tk*/ - - skb = pn533_alloc_skb(dev, skb_len); - if (!skb) - return NULL; - - /* DEP support only */ - *skb_put(skb, 1) = PN533_INIT_TARGET_DEP; - - /* MIFARE params */ - memcpy(skb_put(skb, 6), mifare_params, 6); - - /* Felica params */ - felica = skb_put(skb, 18); - memcpy(felica, felica_params, 18); - get_random_bytes(felica + 2, 6); - - /* NFCID3 */ - nfcid3 = skb_put(skb, 10); - memset(nfcid3, 0, 10); - memcpy(nfcid3, felica, 8); - - /* General bytes */ - *skb_put(skb, 1) = gbytes_len; - - gb = skb_put(skb, gbytes_len); - memcpy(gb, gbytes, gbytes_len); - - /* Len Tk */ - *skb_put(skb, 1) = 0; - - return skb; -} - -#define PN533_CMD_DATAEXCH_HEAD_LEN 1 -#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262 -static void pn533_wq_tm_mi_recv(struct work_struct *work); -static struct sk_buff *pn533_build_response(struct pn533 *dev); - -static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg, - struct sk_buff *resp) -{ - struct sk_buff *skb; - u8 status, ret, mi; - int rc; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (IS_ERR(resp)) { - skb_queue_purge(&dev->resp_q); - return PTR_ERR(resp); - } - - status = resp->data[0]; - - ret = status & PN533_CMD_RET_MASK; - mi = status & PN533_CMD_MI_MASK; - - skb_pull(resp, sizeof(status)); - - if (ret != PN533_CMD_RET_SUCCESS) { - rc = -EIO; - goto error; - } - - skb_queue_tail(&dev->resp_q, resp); - - if (mi) { - queue_work(dev->wq, &dev->mi_tm_rx_work); - return -EINPROGRESS; - } - - skb = pn533_build_response(dev); - if (!skb) { - rc = -EIO; - goto error; - } - - return nfc_tm_data_received(dev->nfc_dev, skb); - -error: - nfc_tm_deactivated(dev->nfc_dev); - dev->tgt_mode = 0; - skb_queue_purge(&dev->resp_q); - dev_kfree_skb(resp); - - return rc; -} - -static void pn533_wq_tm_mi_recv(struct work_struct *work) -{ - struct pn533 *dev = container_of(work, struct pn533, mi_tm_rx_work); - struct sk_buff *skb; - int rc; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - skb = pn533_alloc_skb(dev, 0); - if (!skb) - return; - - rc = pn533_send_cmd_direct_async(dev, - PN533_CMD_TG_GET_DATA, - skb, - pn533_tm_get_data_complete, - NULL); - - if (rc < 0) - dev_kfree_skb(skb); - - return; -} - -static int pn533_tm_send_complete(struct pn533 *dev, void *arg, - struct sk_buff *resp); -static void pn533_wq_tm_mi_send(struct work_struct *work) -{ - struct pn533 *dev = container_of(work, struct pn533, mi_tm_tx_work); - struct sk_buff *skb; - int rc; - - dev_dbg(&dev->interface->dev, "%s\n", __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; - } - - /* last entry - remove MI bit */ - if (skb_queue_len(&dev->fragment_skb) == 0) { - rc = pn533_send_cmd_direct_async(dev, PN533_CMD_TG_SET_DATA, - skb, pn533_tm_send_complete, NULL); - } else - rc = pn533_send_cmd_direct_async(dev, - PN533_CMD_TG_SET_META_DATA, - skb, pn533_tm_send_complete, NULL); - - if (rc == 0) /* success */ - return; - - dev_err(&dev->interface->dev, - "Error %d when trying to perform set meta data_exchange", rc); - - dev_kfree_skb(skb); - -error: - pn533_send_ack(dev, GFP_KERNEL); - queue_work(dev->wq, &dev->cmd_work); -} - -static void pn533_wq_tg_get_data(struct work_struct *work) -{ - struct pn533 *dev = container_of(work, struct pn533, tg_work); - struct sk_buff *skb; - int rc; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - skb = pn533_alloc_skb(dev, 0); - if (!skb) - return; - - rc = pn533_send_data_async(dev, PN533_CMD_TG_GET_DATA, skb, - pn533_tm_get_data_complete, NULL); - - if (rc < 0) - dev_kfree_skb(skb); - - return; -} - -#define ATR_REQ_GB_OFFSET 17 -static int pn533_init_target_complete(struct pn533 *dev, struct sk_buff *resp) -{ - u8 mode, *cmd, comm_mode = NFC_COMM_PASSIVE, *gb; - size_t gb_len; - int rc; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (resp->len < ATR_REQ_GB_OFFSET + 1) - return -EINVAL; - - mode = resp->data[0]; - cmd = &resp->data[1]; - - dev_dbg(&dev->interface->dev, "Target mode 0x%x len %d\n", - mode, resp->len); - - if ((mode & PN533_INIT_TARGET_RESP_FRAME_MASK) == - PN533_INIT_TARGET_RESP_ACTIVE) - comm_mode = NFC_COMM_ACTIVE; - - if ((mode & PN533_INIT_TARGET_RESP_DEP) == 0) /* Only DEP supported */ - return -EOPNOTSUPP; - - gb = cmd + ATR_REQ_GB_OFFSET; - gb_len = resp->len - (ATR_REQ_GB_OFFSET + 1); - - rc = nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, - comm_mode, gb, gb_len); - if (rc < 0) { - nfc_err(&dev->interface->dev, - "Error when signaling target activation\n"); - return rc; - } - - dev->tgt_mode = 1; - queue_work(dev->wq, &dev->tg_work); - - return 0; -} - -static void pn533_listen_mode_timer(unsigned long data) -{ - struct pn533 *dev = (struct pn533 *)data; - - dev_dbg(&dev->interface->dev, "Listen mode timeout\n"); - - dev->cancel_listen = 1; - - pn533_poll_next_mod(dev); - - queue_delayed_work(dev->wq, &dev->poll_work, - msecs_to_jiffies(PN533_POLL_INTERVAL)); -} - -static int pn533_rf_complete(struct pn533 *dev, void *arg, - struct sk_buff *resp) -{ - int rc = 0; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (IS_ERR(resp)) { - rc = PTR_ERR(resp); - - nfc_err(&dev->interface->dev, "RF setting error %d\n", rc); - - return rc; - } - - queue_delayed_work(dev->wq, &dev->poll_work, - msecs_to_jiffies(PN533_POLL_INTERVAL)); - - 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; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - skb = pn533_alloc_skb(dev, 2); - if (!skb) - return; - - *skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD; - *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); - if (rc < 0) { - dev_kfree_skb(skb); - nfc_err(&dev->interface->dev, "RF setting error %d\n", rc); - } - - return; -} - -static int pn533_poll_dep_complete(struct pn533 *dev, void *arg, - struct sk_buff *resp) -{ - struct pn533_cmd_jump_dep_response *rsp; - struct nfc_target nfc_target; - u8 target_gt_len; - int rc; - - if (IS_ERR(resp)) - return PTR_ERR(resp); - - rsp = (struct pn533_cmd_jump_dep_response *)resp->data; - - rc = rsp->status & PN533_CMD_RET_MASK; - if (rc != PN533_CMD_RET_SUCCESS) { - /* Not target found, turn radio off */ - queue_work(dev->wq, &dev->rf_work); - - dev_kfree_skb(resp); - return 0; - } - - dev_dbg(&dev->interface->dev, "Creating new target"); - - nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK; - nfc_target.nfcid1_len = 10; - memcpy(nfc_target.nfcid1, rsp->nfcid3t, nfc_target.nfcid1_len); - rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1); - if (rc) - goto error; - - dev->tgt_available_prots = 0; - dev->tgt_active_prot = NFC_PROTO_NFC_DEP; - - /* ATR_RES general bytes are located at offset 17 */ - target_gt_len = resp->len - 17; - rc = nfc_set_remote_general_bytes(dev->nfc_dev, - rsp->gt, target_gt_len); - if (!rc) { - rc = nfc_dep_link_is_up(dev->nfc_dev, - dev->nfc_dev->targets[0].idx, - 0, NFC_RF_INITIATOR); - - if (!rc) - pn533_poll_reset_mod_list(dev); - } -error: - dev_kfree_skb(resp); - return rc; -} - -#define PASSIVE_DATA_LEN 5 -static int pn533_poll_dep(struct nfc_dev *nfc_dev) -{ - struct pn533 *dev = nfc_get_drvdata(nfc_dev); - struct sk_buff *skb; - int rc, skb_len; - u8 *next, nfcid3[NFC_NFCID3_MAXSIZE]; - u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3}; - - dev_dbg(&dev->interface->dev, "%s", __func__); - - if (!dev->gb) { - dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len); - - if (!dev->gb || !dev->gb_len) { - dev->poll_dep = 0; - queue_work(dev->wq, &dev->rf_work); - } - } - - skb_len = 3 + dev->gb_len; /* ActPass + BR + Next */ - skb_len += PASSIVE_DATA_LEN; - - /* NFCID3 */ - skb_len += NFC_NFCID3_MAXSIZE; - 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) = 0x01; /* Active */ - *skb_put(skb, 1) = 0x02; /* 424 kbps */ - - next = skb_put(skb, 1); /* Next */ - *next = 0; - - /* Copy passive data */ - memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, PASSIVE_DATA_LEN); - *next |= 1; - - /* Copy NFCID3 (which is NFCID2 from SENSF_RES) */ - memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), nfcid3, - NFC_NFCID3_MAXSIZE); - *next |= 2; - - memcpy(skb_put(skb, dev->gb_len), dev->gb, dev->gb_len); - *next |= 4; /* We have some Gi */ - - rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb, - pn533_poll_dep_complete, NULL); - - if (rc < 0) - dev_kfree_skb(skb); - - return rc; -} - -static int pn533_poll_complete(struct pn533 *dev, void *arg, - struct sk_buff *resp) -{ - struct pn533_poll_modulations *cur_mod; - int rc; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (IS_ERR(resp)) { - rc = PTR_ERR(resp); - - nfc_err(&dev->interface->dev, "%s Poll complete error %d\n", - __func__, rc); - - if (rc == -ENOENT) { - if (dev->poll_mod_count != 0) - return rc; - else - goto stop_poll; - } else if (rc < 0) { - nfc_err(&dev->interface->dev, - "Error %d when running poll\n", rc); - goto stop_poll; - } - } - - cur_mod = dev->poll_mod_active[dev->poll_mod_curr]; - - if (cur_mod->len == 0) { /* Target mode */ - del_timer(&dev->listen_timer); - rc = pn533_init_target_complete(dev, resp); - goto done; - } - - /* Initiator mode */ - rc = pn533_start_poll_complete(dev, resp); - if (!rc) - goto done; - - if (!dev->poll_mod_count) { - dev_dbg(&dev->interface->dev, "Polling has been stopped\n"); - goto done; - } - - pn533_poll_next_mod(dev); - /* Not target found, turn radio off */ - queue_work(dev->wq, &dev->rf_work); - -done: - dev_kfree_skb(resp); - return rc; - -stop_poll: - nfc_err(&dev->interface->dev, "Polling operation has been stopped\n"); - - pn533_poll_reset_mod_list(dev); - dev->poll_protocols = 0; - return rc; -} - -static struct sk_buff *pn533_alloc_poll_in_frame(struct pn533 *dev, - struct pn533_poll_modulations *mod) -{ - struct sk_buff *skb; - - skb = pn533_alloc_skb(dev, mod->len); - if (!skb) - return NULL; - - memcpy(skb_put(skb, mod->len), &mod->data, mod->len); - - return skb; -} - -static int pn533_send_poll_frame(struct pn533 *dev) -{ - struct pn533_poll_modulations *mod; - struct sk_buff *skb; - int rc; - u8 cmd_code; - - mod = dev->poll_mod_active[dev->poll_mod_curr]; - - dev_dbg(&dev->interface->dev, "%s mod len %d\n", - __func__, mod->len); - - if ((dev->poll_protocols & NFC_PROTO_NFC_DEP_MASK) && dev->poll_dep) { - dev->poll_dep = 0; - return pn533_poll_dep(dev->nfc_dev); - } - - if (mod->len == 0) { /* Listen mode */ - cmd_code = PN533_CMD_TG_INIT_AS_TARGET; - skb = pn533_alloc_poll_tg_frame(dev); - } else { /* Polling mode */ - cmd_code = PN533_CMD_IN_LIST_PASSIVE_TARGET; - skb = pn533_alloc_poll_in_frame(dev, mod); - } - - if (!skb) { - nfc_err(&dev->interface->dev, "Failed to allocate skb\n"); - return -ENOMEM; - } - - rc = pn533_send_cmd_async(dev, cmd_code, skb, pn533_poll_complete, - NULL); - if (rc < 0) { - dev_kfree_skb(skb); - nfc_err(&dev->interface->dev, "Polling loop error %d\n", rc); - } - - return rc; -} - -static void pn533_wq_poll(struct work_struct *work) -{ - struct pn533 *dev = container_of(work, struct pn533, poll_work.work); - struct pn533_poll_modulations *cur_mod; - int rc; - - cur_mod = dev->poll_mod_active[dev->poll_mod_curr]; - - dev_dbg(&dev->interface->dev, - "%s cancel_listen %d modulation len %d\n", - __func__, dev->cancel_listen, cur_mod->len); - - if (dev->cancel_listen == 1) { - dev->cancel_listen = 0; - pn533_abort_cmd(dev, GFP_ATOMIC); - } - - rc = pn533_send_poll_frame(dev); - if (rc) - return; - - if (cur_mod->len == 0 && dev->poll_mod_count > 1) - mod_timer(&dev->listen_timer, jiffies + PN533_LISTEN_TIME * HZ); - - return; -} - -static int pn533_start_poll(struct nfc_dev *nfc_dev, - u32 im_protocols, u32 tm_protocols) -{ - struct pn533 *dev = nfc_get_drvdata(nfc_dev); - struct pn533_poll_modulations *cur_mod; - u8 rand_mod; - int rc; - - dev_dbg(&dev->interface->dev, - "%s: im protocols 0x%x tm protocols 0x%x\n", - __func__, im_protocols, tm_protocols); - - if (dev->tgt_active_prot) { - nfc_err(&dev->interface->dev, - "Cannot poll with a target already activated\n"); - return -EBUSY; - } - - if (dev->tgt_mode) { - nfc_err(&dev->interface->dev, - "Cannot poll while already being activated\n"); - return -EBUSY; - } - - if (tm_protocols) { - dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len); - if (dev->gb == NULL) - tm_protocols = 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; - - cur_mod = dev->poll_mod_active[dev->poll_mod_curr]; - - rc = pn533_send_poll_frame(dev); - - /* Start listen timer */ - if (!rc && cur_mod->len == 0 && dev->poll_mod_count > 1) - mod_timer(&dev->listen_timer, jiffies + PN533_LISTEN_TIME * HZ); - - return rc; -} - -static void pn533_stop_poll(struct nfc_dev *nfc_dev) -{ - struct pn533 *dev = nfc_get_drvdata(nfc_dev); - - del_timer(&dev->listen_timer); - - if (!dev->poll_mod_count) { - dev_dbg(&dev->interface->dev, - "Polling operation was not running\n"); - return; - } - - pn533_abort_cmd(dev, GFP_KERNEL); - flush_delayed_work(&dev->poll_work); - pn533_poll_reset_mod_list(dev); -} - -static int pn533_activate_target_nfcdep(struct pn533 *dev) -{ - struct pn533_cmd_activate_response *rsp; - u16 gt_len; - int rc; - struct sk_buff *skb; - struct sk_buff *resp; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - skb = pn533_alloc_skb(dev, sizeof(u8) * 2); /*TG + Next*/ - if (!skb) - return -ENOMEM; - - *skb_put(skb, sizeof(u8)) = 1; /* TG */ - *skb_put(skb, sizeof(u8)) = 0; /* Next */ - - resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_ATR, skb); - if (IS_ERR(resp)) - return PTR_ERR(resp); - - rsp = (struct pn533_cmd_activate_response *)resp->data; - rc = rsp->status & PN533_CMD_RET_MASK; - if (rc != PN533_CMD_RET_SUCCESS) { - nfc_err(&dev->interface->dev, - "Target activation failed (error 0x%x)\n", rc); - dev_kfree_skb(resp); - return -EIO; - } - - /* ATR_RES general bytes are located at offset 16 */ - gt_len = resp->len - 16; - rc = nfc_set_remote_general_bytes(dev->nfc_dev, rsp->gt, gt_len); - - dev_kfree_skb(resp); - return rc; -} - -static int pn533_activate_target(struct nfc_dev *nfc_dev, - struct nfc_target *target, u32 protocol) -{ - struct pn533 *dev = nfc_get_drvdata(nfc_dev); - int rc; - - dev_dbg(&dev->interface->dev, "%s: protocol=%u\n", __func__, protocol); - - if (dev->poll_mod_count) { - nfc_err(&dev->interface->dev, - "Cannot activate while polling\n"); - return -EBUSY; - } - - if (dev->tgt_active_prot) { - nfc_err(&dev->interface->dev, - "There is already an active target\n"); - return -EBUSY; - } - - if (!dev->tgt_available_prots) { - nfc_err(&dev->interface->dev, - "There is no available target to activate\n"); - return -EINVAL; - } - - if (!(dev->tgt_available_prots & (1 << protocol))) { - nfc_err(&dev->interface->dev, - "Target doesn't support requested proto %u\n", - protocol); - return -EINVAL; - } - - if (protocol == NFC_PROTO_NFC_DEP) { - rc = pn533_activate_target_nfcdep(dev); - if (rc) { - nfc_err(&dev->interface->dev, - "Activating target with DEP failed %d\n", rc); - return rc; - } - } - - dev->tgt_active_prot = protocol; - dev->tgt_available_prots = 0; - - return 0; -} - -static int pn533_deactivate_target_complete(struct pn533 *dev, void *arg, - struct sk_buff *resp) -{ - int rc = 0; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (IS_ERR(resp)) { - rc = PTR_ERR(resp); - - nfc_err(&dev->interface->dev, "Target release error %d\n", rc); - - return rc; - } - - rc = resp->data[0] & PN533_CMD_RET_MASK; - if (rc != PN533_CMD_RET_SUCCESS) - nfc_err(&dev->interface->dev, - "Error 0x%x when releasing the target\n", rc); - - dev_kfree_skb(resp); - return rc; -} - -static void pn533_deactivate_target(struct nfc_dev *nfc_dev, - struct nfc_target *target, u8 mode) -{ - struct pn533 *dev = nfc_get_drvdata(nfc_dev); - struct sk_buff *skb; - int rc; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (!dev->tgt_active_prot) { - nfc_err(&dev->interface->dev, "There is no active target\n"); - return; - } - - dev->tgt_active_prot = 0; - skb_queue_purge(&dev->resp_q); - - skb = pn533_alloc_skb(dev, sizeof(u8)); - if (!skb) - return; - - *skb_put(skb, 1) = 1; /* TG*/ - - rc = pn533_send_cmd_async(dev, PN533_CMD_IN_RELEASE, skb, - pn533_deactivate_target_complete, NULL); - if (rc < 0) { - dev_kfree_skb(skb); - nfc_err(&dev->interface->dev, "Target release error %d\n", rc); - } - - return; -} - - -static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, - struct sk_buff *resp) -{ - struct pn533_cmd_jump_dep_response *rsp; - u8 target_gt_len; - int rc; - u8 active = *(u8 *)arg; - - kfree(arg); - - if (IS_ERR(resp)) - return PTR_ERR(resp); - - if (dev->tgt_available_prots && - !(dev->tgt_available_prots & (1 << NFC_PROTO_NFC_DEP))) { - nfc_err(&dev->interface->dev, - "The target does not support DEP\n"); - rc = -EINVAL; - goto error; - } - - rsp = (struct pn533_cmd_jump_dep_response *)resp->data; - - rc = rsp->status & PN533_CMD_RET_MASK; - if (rc != PN533_CMD_RET_SUCCESS) { - nfc_err(&dev->interface->dev, - "Bringing DEP link up failed (error 0x%x)\n", rc); - goto error; - } - - if (!dev->tgt_available_prots) { - struct nfc_target nfc_target; - - dev_dbg(&dev->interface->dev, "Creating new target\n"); - - nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK; - nfc_target.nfcid1_len = 10; - memcpy(nfc_target.nfcid1, rsp->nfcid3t, nfc_target.nfcid1_len); - rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1); - if (rc) - goto error; - - dev->tgt_available_prots = 0; - } - - dev->tgt_active_prot = NFC_PROTO_NFC_DEP; - - /* ATR_RES general bytes are located at offset 17 */ - target_gt_len = resp->len - 17; - rc = nfc_set_remote_general_bytes(dev->nfc_dev, - rsp->gt, target_gt_len); - if (rc == 0) - rc = nfc_dep_link_is_up(dev->nfc_dev, - dev->nfc_dev->targets[0].idx, - !active, NFC_RF_INITIATOR); - -error: - dev_kfree_skb(resp); - return rc; -} - -static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf); -static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, - u8 comm_mode, u8 *gb, size_t gb_len) -{ - struct pn533 *dev = nfc_get_drvdata(nfc_dev); - struct sk_buff *skb; - int rc, skb_len; - u8 *next, *arg, nfcid3[NFC_NFCID3_MAXSIZE]; - u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3}; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (dev->poll_mod_count) { - nfc_err(&dev->interface->dev, - "Cannot bring the DEP link up while polling\n"); - return -EBUSY; - } - - if (dev->tgt_active_prot) { - nfc_err(&dev->interface->dev, - "There is already an active target\n"); - return -EBUSY; - } - - skb_len = 3 + gb_len; /* ActPass + BR + Next */ - skb_len += PASSIVE_DATA_LEN; - - /* 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) = 0x02; /* 424 kbps */ - - next = skb_put(skb, 1); /* Next */ - *next = 0; - - /* Copy passive data */ - memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, PASSIVE_DATA_LEN); - *next |= 1; - - /* 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); - 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); - *next |= 4; /* We have some Gi */ - } else { - *next = 0; - } - - arg = kmalloc(sizeof(*arg), GFP_KERNEL); - if (!arg) { - dev_kfree_skb(skb); - return -ENOMEM; - } - - *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); - - if (rc < 0) { - dev_kfree_skb(skb); - kfree(arg); - } - - return rc; -} - -static int pn533_dep_link_down(struct nfc_dev *nfc_dev) -{ - struct pn533 *dev = nfc_get_drvdata(nfc_dev); - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - pn533_poll_reset_mod_list(dev); - - if (dev->tgt_mode || dev->tgt_active_prot) - pn533_abort_cmd(dev, GFP_KERNEL); - - dev->tgt_active_prot = 0; - dev->tgt_mode = 0; - - skb_queue_purge(&dev->resp_q); - - return 0; -} - -struct pn533_data_exchange_arg { - data_exchange_cb_t cb; - void *cb_context; -}; - -static struct sk_buff *pn533_build_response(struct pn533 *dev) -{ - struct sk_buff *skb, *tmp, *t; - unsigned int skb_len = 0, tmp_len = 0; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (skb_queue_empty(&dev->resp_q)) - return NULL; - - if (skb_queue_len(&dev->resp_q) == 1) { - skb = skb_dequeue(&dev->resp_q); - goto out; - } - - skb_queue_walk_safe(&dev->resp_q, tmp, t) - skb_len += tmp->len; - - dev_dbg(&dev->interface->dev, "%s total length %d\n", - __func__, skb_len); - - skb = alloc_skb(skb_len, GFP_KERNEL); - if (skb == NULL) - goto out; - - skb_put(skb, skb_len); - - skb_queue_walk_safe(&dev->resp_q, tmp, t) { - memcpy(skb->data + tmp_len, tmp->data, tmp->len); - tmp_len += tmp->len; - } - -out: - skb_queue_purge(&dev->resp_q); - - return skb; -} - -static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, - struct sk_buff *resp) -{ - struct pn533_data_exchange_arg *arg = _arg; - struct sk_buff *skb; - int rc = 0; - u8 status, ret, mi; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (IS_ERR(resp)) { - rc = PTR_ERR(resp); - goto _error; - } - - status = resp->data[0]; - ret = status & PN533_CMD_RET_MASK; - mi = status & PN533_CMD_MI_MASK; - - skb_pull(resp, sizeof(status)); - - if (ret != PN533_CMD_RET_SUCCESS) { - nfc_err(&dev->interface->dev, - "Exchanging data failed (error 0x%x)\n", ret); - rc = -EIO; - goto error; - } - - skb_queue_tail(&dev->resp_q, resp); - - if (mi) { - dev->cmd_complete_mi_arg = arg; - 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; - } - - skb = pn533_build_response(dev); - if (!skb) { - rc = -ENOMEM; - goto error; - } - - arg->cb(arg->cb_context, skb, 0); - kfree(arg); - return 0; - -error: - dev_kfree_skb(resp); -_error: - skb_queue_purge(&dev->resp_q); - arg->cb(arg->cb_context, NULL, rc); - kfree(arg); - 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; - } - - if (!dev->tgt_mode) { - /* 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) -{ - struct pn533 *dev = nfc_get_drvdata(nfc_dev); - struct pn533_data_exchange_arg *arg = NULL; - int rc; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (!dev->tgt_active_prot) { - nfc_err(&dev->interface->dev, - "Can't exchange data if there is no active target\n"); - rc = -EINVAL; - goto error; - } - - arg = kmalloc(sizeof(*arg), GFP_KERNEL); - if (!arg) { - rc = -ENOMEM; - goto error; - } - - arg->cb = cb; - arg->cb_context = cb_context; - - switch (dev->device_type) { - case PN533_DEVICE_PASORI: - if (dev->tgt_active_prot == NFC_PROTO_FELICA) { - rc = pn533_send_data_async(dev, PN533_CMD_IN_COMM_THRU, - skb, - pn533_data_exchange_complete, - arg); - - break; - } - default: - /* 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, - arg); - - break; - } - - if (rc < 0) /* rc from send_async */ - goto error; - - return 0; - -error: - kfree(arg); - dev_kfree_skb(skb); - return rc; -} - -static int pn533_tm_send_complete(struct pn533 *dev, void *arg, - struct sk_buff *resp) -{ - u8 status; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - if (IS_ERR(resp)) - return PTR_ERR(resp); - - status = resp->data[0]; - - /* Prepare for the next round */ - if (skb_queue_len(&dev->fragment_skb) > 0) { - queue_work(dev->wq, &dev->mi_tm_tx_work); - return -EINPROGRESS; - } - dev_kfree_skb(resp); - - if (status != 0) { - nfc_tm_deactivated(dev->nfc_dev); - - dev->tgt_mode = 0; - - return 0; - } - - queue_work(dev->wq, &dev->tg_work); - - return 0; -} - -static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) -{ - struct pn533 *dev = nfc_get_drvdata(nfc_dev); - int rc; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - /* let's split in multiple chunks if size's too big */ - if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) { - rc = pn533_fill_fragment_skbs(dev, skb); - if (rc <= 0) - goto error; - - /* get the first skb */ - skb = skb_dequeue(&dev->fragment_skb); - if (!skb) { - rc = -EIO; - goto error; - } - - rc = pn533_send_data_async(dev, PN533_CMD_TG_SET_META_DATA, skb, - pn533_tm_send_complete, NULL); - } else { - /* Send th skb */ - rc = pn533_send_data_async(dev, PN533_CMD_TG_SET_DATA, skb, - pn533_tm_send_complete, NULL); - } - -error: - if (rc < 0) { - dev_kfree_skb(skb); - skb_queue_purge(&dev->fragment_skb); - } - - return rc; -} - -static void pn533_wq_mi_recv(struct work_struct *work) -{ - struct pn533 *dev = container_of(work, struct pn533, mi_rx_work); - struct sk_buff *skb; - int rc; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - skb = pn533_alloc_skb(dev, PN533_CMD_DATAEXCH_HEAD_LEN); - if (!skb) - goto error; - - switch (dev->device_type) { - case PN533_DEVICE_PASORI: - if (dev->tgt_active_prot == NFC_PROTO_FELICA) { - rc = pn533_send_cmd_direct_async(dev, - PN533_CMD_IN_COMM_THRU, - skb, - pn533_data_exchange_complete, - dev->cmd_complete_mi_arg); - - break; - } - default: - *skb_put(skb, sizeof(u8)) = 1; /*TG*/ - - rc = pn533_send_cmd_direct_async(dev, - PN533_CMD_IN_DATA_EXCHANGE, - skb, - pn533_data_exchange_complete, - dev->cmd_complete_mi_arg); - - break; - } - - if (rc == 0) /* success */ - return; - - nfc_err(&dev->interface->dev, - "Error %d when trying to perform data_exchange\n", rc); - - dev_kfree_skb(skb); - kfree(dev->cmd_complete_mi_arg); - -error: - pn533_send_ack(dev, GFP_KERNEL); - 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; - - dev_dbg(&dev->interface->dev, "%s\n", __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_err(&dev->interface->dev, - "Error %d when trying to perform data_exchange\n", 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) -{ - struct sk_buff *skb; - struct sk_buff *resp; - int skb_len; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - skb_len = sizeof(cfgitem) + cfgdata_len; /* cfgitem + cfgdata */ - - skb = pn533_alloc_skb(dev, skb_len); - if (!skb) - return -ENOMEM; - - *skb_put(skb, sizeof(cfgitem)) = cfgitem; - memcpy(skb_put(skb, cfgdata_len), cfgdata, cfgdata_len); - - resp = pn533_send_cmd_sync(dev, PN533_CMD_RF_CONFIGURATION, skb); - if (IS_ERR(resp)) - return PTR_ERR(resp); - - dev_kfree_skb(resp); - return 0; -} - -static int pn533_get_firmware_version(struct pn533 *dev, - struct pn533_fw_version *fv) -{ - struct sk_buff *skb; - struct sk_buff *resp; - - skb = pn533_alloc_skb(dev, 0); - if (!skb) - return -ENOMEM; - - resp = pn533_send_cmd_sync(dev, PN533_CMD_GET_FIRMWARE_VERSION, skb); - if (IS_ERR(resp)) - return PTR_ERR(resp); - - fv->ic = resp->data[0]; - fv->ver = resp->data[1]; - fv->rev = resp->data[2]; - fv->support = resp->data[3]; - - dev_kfree_skb(resp); - return 0; -} - -static int pn533_pasori_fw_reset(struct pn533 *dev) -{ - struct sk_buff *skb; - struct sk_buff *resp; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - skb = pn533_alloc_skb(dev, sizeof(u8)); - if (!skb) - return -ENOMEM; - - *skb_put(skb, sizeof(u8)) = 0x1; - - resp = pn533_send_cmd_sync(dev, 0x18, skb); - if (IS_ERR(resp)) - return PTR_ERR(resp); - - dev_kfree_skb(resp); - - return 0; -} - -struct pn533_acr122_poweron_rdr_arg { - int rc; - struct completion done; -}; - -static void pn533_acr122_poweron_rdr_resp(struct urb *urb) -{ - struct pn533_acr122_poweron_rdr_arg *arg = urb->context; - - dev_dbg(&urb->dev->dev, "%s\n", __func__); - - print_hex_dump_debug("ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1, - urb->transfer_buffer, urb->transfer_buffer_length, - false); - - arg->rc = urb->status; - complete(&arg->done); -} - -static int pn533_acr122_poweron_rdr(struct pn533 *dev) -{ - /* Power on th reader (CCID cmd) */ - u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON, - 0, 0, 0, 0, 0, 0, 3, 0, 0}; - u8 buf[255]; - int rc; - void *cntx; - struct pn533_acr122_poweron_rdr_arg arg; - - dev_dbg(&dev->interface->dev, "%s\n", __func__); - - init_completion(&arg.done); - cntx = dev->in_urb->context; /* backup context */ - - dev->in_urb->transfer_buffer = buf; - dev->in_urb->transfer_buffer_length = 255; - dev->in_urb->complete = pn533_acr122_poweron_rdr_resp; - dev->in_urb->context = &arg; - - dev->out_urb->transfer_buffer = cmd; - dev->out_urb->transfer_buffer_length = sizeof(cmd); - - print_hex_dump_debug("ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1, - cmd, sizeof(cmd), false); - - rc = usb_submit_urb(dev->out_urb, GFP_KERNEL); - if (rc) { - nfc_err(&dev->interface->dev, - "Reader power on cmd error %d\n", rc); - return rc; - } - - rc = usb_submit_urb(dev->in_urb, GFP_KERNEL); - if (rc) { - nfc_err(&dev->interface->dev, - "Can't submit reader poweron cmd response %d\n", rc); - return rc; - } - - wait_for_completion(&arg.done); - dev->in_urb->context = cntx; /* restore context */ - - return arg.rc; -} - -static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf) -{ - struct pn533 *dev = nfc_get_drvdata(nfc_dev); - 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) { - nfc_err(&dev->interface->dev, "Error on setting RF field\n"); - return rc; - } - - return rc; -} - -static int pn533_dev_up(struct nfc_dev *nfc_dev) -{ - return pn533_rf_field(nfc_dev, 1); -} - -static int pn533_dev_down(struct nfc_dev *nfc_dev) -{ - return pn533_rf_field(nfc_dev, 0); -} - -static struct nfc_ops pn533_nfc_ops = { - .dev_up = pn533_dev_up, - .dev_down = pn533_dev_down, - .dep_link_up = pn533_dep_link_up, - .dep_link_down = pn533_dep_link_down, - .start_poll = pn533_start_poll, - .stop_poll = pn533_stop_poll, - .activate_target = pn533_activate_target, - .deactivate_target = pn533_deactivate_target, - .im_transceive = pn533_transceive, - .tm_send = pn533_tm_send, -}; - -static int pn533_setup(struct pn533 *dev) -{ - struct pn533_config_max_retries max_retries; - struct pn533_config_timing timing; - u8 pasori_cfg[3] = {0x08, 0x01, 0x08}; - int rc; - - switch (dev->device_type) { - case PN533_DEVICE_STD: - case PN533_DEVICE_PASORI: - case PN533_DEVICE_ACR122U: - max_retries.mx_rty_atr = 0x2; - max_retries.mx_rty_psl = 0x1; - 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_102; - timing.dep_timeout = PN533_CONFIG_TIMING_204; - - break; - - default: - nfc_err(&dev->interface->dev, "Unknown device type %d\n", - dev->device_type); - return -EINVAL; - } - - rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES, - (u8 *)&max_retries, sizeof(max_retries)); - if (rc) { - nfc_err(&dev->interface->dev, - "Error on setting MAX_RETRIES config\n"); - return rc; - } - - - rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING, - (u8 *)&timing, sizeof(timing)); - if (rc) { - nfc_err(&dev->interface->dev, "Error on setting RF timings\n"); - return rc; - } - - switch (dev->device_type) { - case PN533_DEVICE_STD: - break; - - case PN533_DEVICE_PASORI: - pn533_pasori_fw_reset(dev); - - rc = pn533_set_configuration(dev, PN533_CFGITEM_PASORI, - pasori_cfg, 3); - if (rc) { - nfc_err(&dev->interface->dev, - "Error while settings PASORI config\n"); - return rc; - } - - pn533_pasori_fw_reset(dev); - - break; - } - - return 0; -} - -static int pn533_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct pn533_fw_version fw_ver; - struct pn533 *dev; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int in_endpoint = 0; - int out_endpoint = 0; - int rc = -ENOMEM; - int i; - u32 protocols; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - dev->udev = usb_get_dev(interface_to_usbdev(interface)); - dev->interface = interface; - mutex_init(&dev->cmd_lock); - - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint)) - in_endpoint = endpoint->bEndpointAddress; - - if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint)) - out_endpoint = endpoint->bEndpointAddress; - } - - if (!in_endpoint || !out_endpoint) { - nfc_err(&interface->dev, - "Could not find bulk-in or bulk-out endpoint\n"); - rc = -ENODEV; - goto error; - } - - dev->in_urb = usb_alloc_urb(0, GFP_KERNEL); - dev->out_urb = usb_alloc_urb(0, GFP_KERNEL); - - if (!dev->in_urb || !dev->out_urb) - goto error; - - usb_fill_bulk_urb(dev->in_urb, dev->udev, - usb_rcvbulkpipe(dev->udev, in_endpoint), - NULL, 0, NULL, dev); - usb_fill_bulk_urb(dev->out_urb, dev->udev, - usb_sndbulkpipe(dev->udev, out_endpoint), - NULL, 0, pn533_send_complete, dev); - - INIT_WORK(&dev->cmd_work, pn533_wq_cmd); - INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete); - 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->mi_tm_rx_work, pn533_wq_tm_mi_recv); - INIT_WORK(&dev->mi_tm_tx_work, pn533_wq_tm_mi_send); - 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) - goto error; - - init_timer(&dev->listen_timer); - dev->listen_timer.data = (unsigned long) dev; - 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); - - usb_set_intfdata(interface, dev); - - dev->ops = &pn533_std_frame_ops; - - dev->protocol_type = PN533_PROTO_REQ_ACK_RESP; - dev->device_type = id->driver_info; - switch (dev->device_type) { - case PN533_DEVICE_STD: - protocols = PN533_ALL_PROTOCOLS; - break; - - case PN533_DEVICE_PASORI: - protocols = PN533_NO_TYPE_B_PROTOCOLS; - break; - - case PN533_DEVICE_ACR122U: - protocols = PN533_NO_TYPE_B_PROTOCOLS; - dev->ops = &pn533_acr122_frame_ops; - dev->protocol_type = PN533_PROTO_REQ_RESP, - - rc = pn533_acr122_poweron_rdr(dev); - if (rc < 0) { - nfc_err(&dev->interface->dev, - "Couldn't poweron the reader (error %d)\n", rc); - goto destroy_wq; - } - break; - - default: - nfc_err(&dev->interface->dev, "Unknown device type %d\n", - dev->device_type); - rc = -EINVAL; - goto destroy_wq; - } - - memset(&fw_ver, 0, sizeof(fw_ver)); - rc = pn533_get_firmware_version(dev, &fw_ver); - if (rc < 0) - goto destroy_wq; - - nfc_info(&dev->interface->dev, - "NXP PN5%02X firmware ver %d.%d now attached\n", - fw_ver.ic, fw_ver.ver, fw_ver.rev); - - - dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols, - dev->ops->tx_header_len + - PN533_CMD_DATAEXCH_HEAD_LEN, - dev->ops->tx_tail_len); - if (!dev->nfc_dev) { - rc = -ENOMEM; - goto destroy_wq; - } - - nfc_set_parent_dev(dev->nfc_dev, &interface->dev); - nfc_set_drvdata(dev->nfc_dev, dev); - - rc = nfc_register_device(dev->nfc_dev); - if (rc) - goto free_nfc_dev; - - rc = pn533_setup(dev); - if (rc) - goto unregister_nfc_dev; - - return 0; - -unregister_nfc_dev: - nfc_unregister_device(dev->nfc_dev); - -free_nfc_dev: - nfc_free_device(dev->nfc_dev); - -destroy_wq: - destroy_workqueue(dev->wq); -error: - usb_free_urb(dev->in_urb); - usb_free_urb(dev->out_urb); - usb_put_dev(dev->udev); - kfree(dev); - return rc; -} - -static void pn533_disconnect(struct usb_interface *interface) -{ - struct pn533 *dev; - struct pn533_cmd *cmd, *n; - - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - - nfc_unregister_device(dev->nfc_dev); - nfc_free_device(dev->nfc_dev); - - 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); - - del_timer(&dev->listen_timer); - - list_for_each_entry_safe(cmd, n, &dev->cmd_queue, queue) { - list_del(&cmd->queue); - kfree(cmd); - } - - usb_free_urb(dev->in_urb); - usb_free_urb(dev->out_urb); - kfree(dev); - - nfc_info(&interface->dev, "NXP PN533 NFC device disconnected\n"); -} - -static struct usb_driver pn533_driver = { - .name = "pn533", - .probe = pn533_probe, - .disconnect = pn533_disconnect, - .id_table = pn533_table, -}; - -module_usb_driver(pn533_driver); - -MODULE_AUTHOR("Lauro Ramos Venancio "); -MODULE_AUTHOR("Aloisio Almeida Jr "); -MODULE_AUTHOR("Waldemar Rymarkiewicz "); -MODULE_DESCRIPTION("PN533 usb driver ver " VERSION); -MODULE_VERSION(VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/nfc/pn533/Kconfig b/drivers/nfc/pn533/Kconfig new file mode 100644 index 000000000000..b5a926e42f7b --- /dev/null +++ b/drivers/nfc/pn533/Kconfig @@ -0,0 +1,16 @@ +config NFC_PN533 + tristate + help + NXP PN533 core driver. + This driver provides core functionality for NXP PN533 NFC devices. + +config NFC_PN533_USB + tristate "NFC PN533 device support (USB)" + depends on USB + select NFC_PN533 + ---help--- + This module adds support for the NXP pn533 USB interface. + Select this if your platform is using the USB bus. + + If you choose to build a module, it'll be called pn533_usb. + Say N if unsure. diff --git a/drivers/nfc/pn533/Makefile b/drivers/nfc/pn533/Makefile new file mode 100644 index 000000000000..12c6be481483 --- /dev/null +++ b/drivers/nfc/pn533/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for PN533 NFC driver +# +pn533_usb-objs = usb.o + +obj-$(CONFIG_NFC_PN533) += pn533.o +obj-$(CONFIG_NFC_PN533_USB) += pn533_usb.o diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c new file mode 100644 index 000000000000..52d83fec5add --- /dev/null +++ b/drivers/nfc/pn533/pn533.c @@ -0,0 +1,2644 @@ +/* + * Driver for NXP PN533 NFC Chip - core functions + * + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * Copyright (C) 2012-2013 Tieto Poland + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include "pn533.h" + +#define VERSION "0.3" + +/* How much time we spend listening for initiators */ +#define PN533_LISTEN_TIME 2 +/* Delay between each poll frame (ms) */ +#define PN533_POLL_INTERVAL 10 + +/* structs for pn533 commands */ + +/* PN533_CMD_GET_FIRMWARE_VERSION */ +struct pn533_fw_version { + u8 ic; + u8 ver; + u8 rev; + u8 support; +}; + +/* PN533_CMD_RF_CONFIGURATION */ +#define PN533_CFGITEM_RF_FIELD 0x01 +#define PN533_CFGITEM_TIMING 0x02 +#define PN533_CFGITEM_MAX_RETRIES 0x05 +#define PN533_CFGITEM_PASORI 0x82 + +#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 +#define PN533_CONFIG_TIMING_409 0xd +#define PN533_CONFIG_TIMING_819 0xe + +#define PN533_CONFIG_MAX_RETRIES_NO_RETRY 0x00 +#define PN533_CONFIG_MAX_RETRIES_ENDLESS 0xFF + +struct pn533_config_max_retries { + u8 mx_rty_atr; + u8 mx_rty_psl; + u8 mx_rty_passive_act; +} __packed; + +struct pn533_config_timing { + u8 rfu; + u8 atr_res_timeout; + u8 dep_timeout; +} __packed; + +/* PN533_CMD_IN_LIST_PASSIVE_TARGET */ + +/* felica commands opcode */ +#define PN533_FELICA_OPC_SENSF_REQ 0 +#define PN533_FELICA_OPC_SENSF_RES 1 +/* felica SENSF_REQ parameters */ +#define PN533_FELICA_SENSF_SC_ALL 0xFFFF +#define PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE 0 +#define PN533_FELICA_SENSF_RC_SYSTEM_CODE 1 +#define PN533_FELICA_SENSF_RC_ADVANCED_PROTOCOL 2 + +/* type B initiator_data values */ +#define PN533_TYPE_B_AFI_ALL_FAMILIES 0 +#define PN533_TYPE_B_POLL_METHOD_TIMESLOT 0 +#define PN533_TYPE_B_POLL_METHOD_PROBABILISTIC 1 + +union pn533_cmd_poll_initdata { + struct { + u8 afi; + u8 polling_method; + } __packed type_b; + struct { + u8 opcode; + __be16 sc; + u8 rc; + u8 tsn; + } __packed felica; +}; + +struct pn533_poll_modulations { + struct { + u8 maxtg; + u8 brty; + union pn533_cmd_poll_initdata initiator_data; + } __packed data; + u8 len; +}; + +static const struct pn533_poll_modulations poll_mod[] = { + [PN533_POLL_MOD_106KBPS_A] = { + .data = { + .maxtg = 1, + .brty = 0, + }, + .len = 2, + }, + [PN533_POLL_MOD_212KBPS_FELICA] = { + .data = { + .maxtg = 1, + .brty = 1, + .initiator_data.felica = { + .opcode = PN533_FELICA_OPC_SENSF_REQ, + .sc = PN533_FELICA_SENSF_SC_ALL, + .rc = PN533_FELICA_SENSF_RC_SYSTEM_CODE, + .tsn = 0x03, + }, + }, + .len = 7, + }, + [PN533_POLL_MOD_424KBPS_FELICA] = { + .data = { + .maxtg = 1, + .brty = 2, + .initiator_data.felica = { + .opcode = PN533_FELICA_OPC_SENSF_REQ, + .sc = PN533_FELICA_SENSF_SC_ALL, + .rc = PN533_FELICA_SENSF_RC_SYSTEM_CODE, + .tsn = 0x03, + }, + }, + .len = 7, + }, + [PN533_POLL_MOD_106KBPS_JEWEL] = { + .data = { + .maxtg = 1, + .brty = 4, + }, + .len = 2, + }, + [PN533_POLL_MOD_847KBPS_B] = { + .data = { + .maxtg = 1, + .brty = 8, + .initiator_data.type_b = { + .afi = PN533_TYPE_B_AFI_ALL_FAMILIES, + .polling_method = + PN533_TYPE_B_POLL_METHOD_TIMESLOT, + }, + }, + .len = 3, + }, + [PN533_LISTEN_MOD] = { + .len = 0, + }, +}; + +/* PN533_CMD_IN_ATR */ + +struct pn533_cmd_activate_response { + u8 status; + u8 nfcid3t[10]; + u8 didt; + u8 bst; + u8 brt; + u8 to; + u8 ppt; + /* optional */ + u8 gt[]; +} __packed; + +struct pn533_cmd_jump_dep_response { + u8 status; + u8 tg; + u8 nfcid3t[10]; + u8 didt; + u8 bst; + u8 brt; + u8 to; + u8 ppt; + /* optional */ + u8 gt[]; +} __packed; + + +/* PN533_TG_INIT_AS_TARGET */ +#define PN533_INIT_TARGET_PASSIVE 0x1 +#define PN533_INIT_TARGET_DEP 0x2 + +#define PN533_INIT_TARGET_RESP_FRAME_MASK 0x3 +#define PN533_INIT_TARGET_RESP_ACTIVE 0x1 +#define PN533_INIT_TARGET_RESP_DEP 0x4 + +/* 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) +{ + return ~value + 1; +} + +/* The rule: sum(data elements) + checksum = 0 */ +static u8 pn533_std_data_checksum(u8 *data, int datalen) +{ + u8 sum = 0; + int i; + + for (i = 0; i < datalen; i++) + sum += data[i]; + + return pn533_std_checksum(sum); +} + +static void pn533_std_tx_frame_init(void *_frame, u8 cmd_code) +{ + struct pn533_std_frame *frame = _frame; + + frame->preamble = 0; + frame->start_frame = cpu_to_be16(PN533_STD_FRAME_SOF); + PN533_STD_FRAME_IDENTIFIER(frame) = PN533_STD_FRAME_DIR_OUT; + PN533_FRAME_CMD(frame) = cmd_code; + frame->datalen = 2; +} + +static void pn533_std_tx_frame_finish(void *_frame) +{ + struct pn533_std_frame *frame = _frame; + + frame->datalen_checksum = pn533_std_checksum(frame->datalen); + + PN533_STD_FRAME_CHECKSUM(frame) = + pn533_std_data_checksum(frame->data, frame->datalen); + + PN533_STD_FRAME_POSTAMBLE(frame) = 0; +} + +static void pn533_std_tx_update_payload_len(void *_frame, int len) +{ + struct pn533_std_frame *frame = _frame; + + frame->datalen += len; +} + +static bool pn533_std_rx_frame_is_valid(void *_frame, struct pn533 *dev) +{ + u8 checksum; + struct pn533_std_frame *stdf = _frame; + + if (stdf->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF)) + return false; + + 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) + 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; + + 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; + + /* 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; +} + +bool pn533_rx_frame_is_ack(void *_frame) +{ + struct pn533_std_frame *frame = _frame; + + if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF)) + return false; + + if (frame->datalen != 0 || frame->datalen_checksum != 0xFF) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(pn533_rx_frame_is_ack); + +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; +} + +static u8 pn533_std_get_cmd_code(void *frame) +{ + struct pn533_std_frame *f = frame; + struct pn533_ext_frame *eif = frame; + + if (PN533_STD_IS_EXTENDED(f)) + return PN533_FRAME_CMD(eif); + else + return PN533_FRAME_CMD(f); +} + +bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame) +{ + return (dev->ops->get_cmd_code(frame) == + PN533_CMD_RESPONSE(dev->cmd->code)); +} +EXPORT_SYMBOL_GPL(pn533_rx_frame_is_cmd_response); + + +static struct pn533_frame_ops pn533_std_frame_ops = { + .tx_frame_init = pn533_std_tx_frame_init, + .tx_frame_finish = pn533_std_tx_frame_finish, + .tx_update_payload_len = pn533_std_tx_update_payload_len, + .tx_header_len = PN533_STD_FRAME_HEADER_LEN, + .tx_tail_len = PN533_STD_FRAME_TAIL_LEN, + + .rx_is_frame_valid = pn533_std_rx_frame_is_valid, + .rx_frame_size = pn533_std_rx_frame_size, + .rx_header_len = PN533_STD_FRAME_HEADER_LEN, + .rx_tail_len = PN533_STD_FRAME_TAIL_LEN, + + .max_payload_len = PN533_STD_FRAME_MAX_PAYLOAD_LEN, + .get_cmd_code = pn533_std_get_cmd_code, +}; + +static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code, + struct sk_buff *skb) +{ + /* payload is already there, just update datalen */ + int payload_len = skb->len; + struct pn533_frame_ops *ops = dev->ops; + + + skb_push(skb, ops->tx_header_len); + skb_put(skb, ops->tx_tail_len); + + ops->tx_frame_init(skb->data, cmd_code); + ops->tx_update_payload_len(skb->data, payload_len); + ops->tx_frame_finish(skb->data); +} + +static int pn533_send_async_complete(struct pn533 *dev) +{ + struct pn533_cmd *cmd = dev->cmd; + int status = cmd->status; + + struct sk_buff *req = cmd->req; + struct sk_buff *resp = cmd->resp; + + int rc; + + dev_kfree_skb(req); + + if (status < 0) { + rc = cmd->complete_cb(dev, cmd->complete_cb_context, + ERR_PTR(status)); + dev_kfree_skb(resp); + goto done; + } + + skb_pull(resp, dev->ops->rx_header_len); + skb_trim(resp, resp->len - dev->ops->rx_tail_len); + + rc = cmd->complete_cb(dev, cmd->complete_cb_context, resp); + +done: + kfree(cmd); + dev->cmd = NULL; + return rc; +} + +static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, + struct sk_buff *req, + pn533_send_async_complete_t complete_cb, + void *complete_cb_context) +{ + struct pn533_cmd *cmd; + int rc = 0; + + dev_dbg(dev->dev, "Sending command 0x%x\n", cmd_code); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->code = cmd_code; + cmd->req = req; + cmd->complete_cb = complete_cb; + cmd->complete_cb_context = complete_cb_context; + + pn533_build_cmd_frame(dev, cmd_code, req); + + mutex_lock(&dev->cmd_lock); + + if (!dev->cmd_pending) { + rc = dev->phy_ops->send_frame(dev, req); + if (rc) + goto error; + + dev->cmd_pending = 1; + dev->cmd = cmd; + goto unlock; + } + + dev_dbg(dev->dev, "%s Queueing command 0x%x\n", + __func__, cmd_code); + + INIT_LIST_HEAD(&cmd->queue); + list_add_tail(&cmd->queue, &dev->cmd_queue); + + goto unlock; + +error: + kfree(cmd); +unlock: + mutex_unlock(&dev->cmd_lock); + return rc; +} + +static int pn533_send_data_async(struct pn533 *dev, u8 cmd_code, + struct sk_buff *req, + pn533_send_async_complete_t complete_cb, + void *complete_cb_context) +{ + int rc; + + rc = __pn533_send_async(dev, cmd_code, req, complete_cb, + complete_cb_context); + + return rc; +} + +static int pn533_send_cmd_async(struct pn533 *dev, u8 cmd_code, + struct sk_buff *req, + pn533_send_async_complete_t complete_cb, + void *complete_cb_context) +{ + int rc; + + rc = __pn533_send_async(dev, cmd_code, req, complete_cb, + complete_cb_context); + + return rc; +} + +/* + * pn533_send_cmd_direct_async + * + * The function sends a piority cmd directly to the chip omiting the cmd + * queue. It's intended to be used by chaining mechanism of received responses + * where the host has to request every single chunk of data before scheduling + * next cmd from the queue. + */ +static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, + struct sk_buff *req, + pn533_send_async_complete_t complete_cb, + void *complete_cb_context) +{ + struct pn533_cmd *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->code = cmd_code; + cmd->req = req; + cmd->complete_cb = complete_cb; + cmd->complete_cb_context = complete_cb_context; + + pn533_build_cmd_frame(dev, cmd_code, req); + + rc = dev->phy_ops->send_frame(dev, req); + if (rc < 0) + kfree(cmd); + else + dev->cmd = cmd; + + return rc; +} + +static void pn533_wq_cmd_complete(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work); + int rc; + + rc = pn533_send_async_complete(dev); + if (rc != -EINPROGRESS) + queue_work(dev->wq, &dev->cmd_work); +} + +static void pn533_wq_cmd(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, cmd_work); + struct pn533_cmd *cmd; + int rc; + + mutex_lock(&dev->cmd_lock); + + if (list_empty(&dev->cmd_queue)) { + dev->cmd_pending = 0; + mutex_unlock(&dev->cmd_lock); + return; + } + + cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); + + list_del(&cmd->queue); + + mutex_unlock(&dev->cmd_lock); + + rc = dev->phy_ops->send_frame(dev, cmd->req); + if (rc < 0) { + dev_kfree_skb(cmd->req); + kfree(cmd); + return; + } + + dev->cmd = cmd; +} + +struct pn533_sync_cmd_response { + struct sk_buff *resp; + struct completion done; +}; + +static int pn533_send_sync_complete(struct pn533 *dev, void *_arg, + struct sk_buff *resp) +{ + struct pn533_sync_cmd_response *arg = _arg; + + arg->resp = resp; + complete(&arg->done); + + return 0; +} + +/* pn533_send_cmd_sync + * + * Please note the req parameter is freed inside the function to + * limit a number of return value interpretations by the caller. + * + * 1. negative in case of error during TX path -> req should be freed + * + * 2. negative in case of error during RX path -> req should not be freed + * as it's been already freed at the beginning of RX path by + * async_complete_cb. + * + * 3. valid pointer in case of succesfult RX path + * + * A caller has to check a return value with IS_ERR macro. If the test pass, + * the returned pointer is valid. + * + */ +static struct sk_buff *pn533_send_cmd_sync(struct pn533 *dev, u8 cmd_code, + struct sk_buff *req) +{ + int rc; + struct pn533_sync_cmd_response arg; + + init_completion(&arg.done); + + rc = pn533_send_cmd_async(dev, cmd_code, req, + pn533_send_sync_complete, &arg); + if (rc) { + dev_kfree_skb(req); + return ERR_PTR(rc); + } + + wait_for_completion(&arg.done); + + return arg.resp; +} + +static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size) +{ + struct sk_buff *skb; + + skb = alloc_skb(dev->ops->tx_header_len + + size + + dev->ops->tx_tail_len, GFP_KERNEL); + + if (skb) + skb_reserve(skb, dev->ops->tx_header_len); + + return skb; +} + +struct pn533_target_type_a { + __be16 sens_res; + u8 sel_res; + u8 nfcid_len; + u8 nfcid_data[]; +} __packed; + + +#define PN533_TYPE_A_SENS_RES_NFCID1(x) ((u8)((be16_to_cpu(x) & 0x00C0) >> 6)) +#define PN533_TYPE_A_SENS_RES_SSD(x) ((u8)((be16_to_cpu(x) & 0x001F) >> 0)) +#define PN533_TYPE_A_SENS_RES_PLATCONF(x) ((u8)((be16_to_cpu(x) & 0x0F00) >> 8)) + +#define PN533_TYPE_A_SENS_RES_SSD_JEWEL 0x00 +#define PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL 0x0C + +#define PN533_TYPE_A_SEL_PROT(x) (((x) & 0x60) >> 5) +#define PN533_TYPE_A_SEL_CASCADE(x) (((x) & 0x04) >> 2) + +#define PN533_TYPE_A_SEL_PROT_MIFARE 0 +#define PN533_TYPE_A_SEL_PROT_ISO14443 1 +#define PN533_TYPE_A_SEL_PROT_DEP 2 +#define PN533_TYPE_A_SEL_PROT_ISO14443_DEP 3 + +static bool pn533_target_type_a_is_valid(struct pn533_target_type_a *type_a, + int target_data_len) +{ + u8 ssd; + u8 platconf; + + if (target_data_len < sizeof(struct pn533_target_type_a)) + return false; + + /* + * The length check of nfcid[] and ats[] are not being performed because + * the values are not being used + */ + + /* Requirement 4.6.3.3 from NFC Forum Digital Spec */ + ssd = PN533_TYPE_A_SENS_RES_SSD(type_a->sens_res); + platconf = PN533_TYPE_A_SENS_RES_PLATCONF(type_a->sens_res); + + if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL && + platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) || + (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL && + platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL)) + return false; + + /* Requirements 4.8.2.1, 4.8.2.3, 4.8.2.5 and 4.8.2.7 from NFC Forum */ + if (PN533_TYPE_A_SEL_CASCADE(type_a->sel_res) != 0) + return false; + + return true; +} + +static int pn533_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data, + int tgt_data_len) +{ + struct pn533_target_type_a *tgt_type_a; + + tgt_type_a = (struct pn533_target_type_a *)tgt_data; + + if (!pn533_target_type_a_is_valid(tgt_type_a, tgt_data_len)) + return -EPROTO; + + switch (PN533_TYPE_A_SEL_PROT(tgt_type_a->sel_res)) { + case PN533_TYPE_A_SEL_PROT_MIFARE: + nfc_tgt->supported_protocols = NFC_PROTO_MIFARE_MASK; + break; + case PN533_TYPE_A_SEL_PROT_ISO14443: + nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK; + break; + case PN533_TYPE_A_SEL_PROT_DEP: + nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK; + break; + case PN533_TYPE_A_SEL_PROT_ISO14443_DEP: + nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK | + NFC_PROTO_NFC_DEP_MASK; + break; + } + + nfc_tgt->sens_res = be16_to_cpu(tgt_type_a->sens_res); + nfc_tgt->sel_res = tgt_type_a->sel_res; + nfc_tgt->nfcid1_len = tgt_type_a->nfcid_len; + memcpy(nfc_tgt->nfcid1, tgt_type_a->nfcid_data, nfc_tgt->nfcid1_len); + + return 0; +} + +struct pn533_target_felica { + u8 pol_res; + u8 opcode; + u8 nfcid2[NFC_NFCID2_MAXSIZE]; + u8 pad[8]; + /* optional */ + u8 syst_code[]; +} __packed; + +#define PN533_FELICA_SENSF_NFCID2_DEP_B1 0x01 +#define PN533_FELICA_SENSF_NFCID2_DEP_B2 0xFE + +static bool pn533_target_felica_is_valid(struct pn533_target_felica *felica, + int target_data_len) +{ + if (target_data_len < sizeof(struct pn533_target_felica)) + return false; + + if (felica->opcode != PN533_FELICA_OPC_SENSF_RES) + return false; + + return true; +} + +static int pn533_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data, + int tgt_data_len) +{ + struct pn533_target_felica *tgt_felica; + + tgt_felica = (struct pn533_target_felica *)tgt_data; + + if (!pn533_target_felica_is_valid(tgt_felica, tgt_data_len)) + return -EPROTO; + + if ((tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1) && + (tgt_felica->nfcid2[1] == PN533_FELICA_SENSF_NFCID2_DEP_B2)) + nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK; + else + nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK; + + memcpy(nfc_tgt->sensf_res, &tgt_felica->opcode, 9); + nfc_tgt->sensf_res_len = 9; + + memcpy(nfc_tgt->nfcid2, tgt_felica->nfcid2, NFC_NFCID2_MAXSIZE); + nfc_tgt->nfcid2_len = NFC_NFCID2_MAXSIZE; + + return 0; +} + +struct pn533_target_jewel { + __be16 sens_res; + u8 jewelid[4]; +} __packed; + +static bool pn533_target_jewel_is_valid(struct pn533_target_jewel *jewel, + int target_data_len) +{ + u8 ssd; + u8 platconf; + + if (target_data_len < sizeof(struct pn533_target_jewel)) + return false; + + /* Requirement 4.6.3.3 from NFC Forum Digital Spec */ + ssd = PN533_TYPE_A_SENS_RES_SSD(jewel->sens_res); + platconf = PN533_TYPE_A_SENS_RES_PLATCONF(jewel->sens_res); + + if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL && + platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) || + (ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL && + platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL)) + return false; + + return true; +} + +static int pn533_target_found_jewel(struct nfc_target *nfc_tgt, u8 *tgt_data, + int tgt_data_len) +{ + struct pn533_target_jewel *tgt_jewel; + + tgt_jewel = (struct pn533_target_jewel *)tgt_data; + + if (!pn533_target_jewel_is_valid(tgt_jewel, tgt_data_len)) + return -EPROTO; + + nfc_tgt->supported_protocols = NFC_PROTO_JEWEL_MASK; + nfc_tgt->sens_res = be16_to_cpu(tgt_jewel->sens_res); + nfc_tgt->nfcid1_len = 4; + memcpy(nfc_tgt->nfcid1, tgt_jewel->jewelid, nfc_tgt->nfcid1_len); + + return 0; +} + +struct pn533_type_b_prot_info { + u8 bitrate; + u8 fsci_type; + u8 fwi_adc_fo; +} __packed; + +#define PN533_TYPE_B_PROT_FCSI(x) (((x) & 0xF0) >> 4) +#define PN533_TYPE_B_PROT_TYPE(x) (((x) & 0x0F) >> 0) +#define PN533_TYPE_B_PROT_TYPE_RFU_MASK 0x8 + +struct pn533_type_b_sens_res { + u8 opcode; + u8 nfcid[4]; + u8 appdata[4]; + struct pn533_type_b_prot_info prot_info; +} __packed; + +#define PN533_TYPE_B_OPC_SENSB_RES 0x50 + +struct pn533_target_type_b { + struct pn533_type_b_sens_res sensb_res; + u8 attrib_res_len; + u8 attrib_res[]; +} __packed; + +static bool pn533_target_type_b_is_valid(struct pn533_target_type_b *type_b, + int target_data_len) +{ + if (target_data_len < sizeof(struct pn533_target_type_b)) + return false; + + if (type_b->sensb_res.opcode != PN533_TYPE_B_OPC_SENSB_RES) + return false; + + if (PN533_TYPE_B_PROT_TYPE(type_b->sensb_res.prot_info.fsci_type) & + PN533_TYPE_B_PROT_TYPE_RFU_MASK) + return false; + + return true; +} + +static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data, + int tgt_data_len) +{ + struct pn533_target_type_b *tgt_type_b; + + tgt_type_b = (struct pn533_target_type_b *)tgt_data; + + if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len)) + return -EPROTO; + + nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_B_MASK; + + return 0; +} + +static int pn533_target_found(struct pn533 *dev, u8 tg, u8 *tgdata, + int tgdata_len) +{ + struct nfc_target nfc_tgt; + int rc; + + dev_dbg(dev->dev, "%s: modulation=%d\n", + __func__, dev->poll_mod_curr); + + if (tg != 1) + return -EPROTO; + + memset(&nfc_tgt, 0, sizeof(struct nfc_target)); + + switch (dev->poll_mod_curr) { + case PN533_POLL_MOD_106KBPS_A: + rc = pn533_target_found_type_a(&nfc_tgt, tgdata, tgdata_len); + break; + case PN533_POLL_MOD_212KBPS_FELICA: + case PN533_POLL_MOD_424KBPS_FELICA: + rc = pn533_target_found_felica(&nfc_tgt, tgdata, tgdata_len); + break; + case PN533_POLL_MOD_106KBPS_JEWEL: + rc = pn533_target_found_jewel(&nfc_tgt, tgdata, tgdata_len); + break; + case PN533_POLL_MOD_847KBPS_B: + rc = pn533_target_found_type_b(&nfc_tgt, tgdata, tgdata_len); + break; + default: + nfc_err(dev->dev, + "Unknown current poll modulation\n"); + return -EPROTO; + } + + if (rc) + return rc; + + if (!(nfc_tgt.supported_protocols & dev->poll_protocols)) { + dev_dbg(dev->dev, + "The Tg found doesn't have the desired protocol\n"); + return -EAGAIN; + } + + dev_dbg(dev->dev, + "Target found - supported protocols: 0x%x\n", + nfc_tgt.supported_protocols); + + dev->tgt_available_prots = nfc_tgt.supported_protocols; + + nfc_targets_found(dev->nfc_dev, &nfc_tgt, 1); + + return 0; +} + +static inline void pn533_poll_next_mod(struct pn533 *dev) +{ + dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count; +} + +static void pn533_poll_reset_mod_list(struct pn533 *dev) +{ + dev->poll_mod_count = 0; +} + +static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index) +{ + dev->poll_mod_active[dev->poll_mod_count] = + (struct pn533_poll_modulations *)&poll_mod[mod_index]; + dev->poll_mod_count++; +} + +static void pn533_poll_create_mod_list(struct pn533 *dev, + u32 im_protocols, u32 tm_protocols) +{ + pn533_poll_reset_mod_list(dev); + + if ((im_protocols & NFC_PROTO_MIFARE_MASK) || + (im_protocols & NFC_PROTO_ISO14443_MASK) || + (im_protocols & NFC_PROTO_NFC_DEP_MASK)) + pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A); + + if (im_protocols & NFC_PROTO_FELICA_MASK || + im_protocols & NFC_PROTO_NFC_DEP_MASK) { + pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA); + pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA); + } + + if (im_protocols & NFC_PROTO_JEWEL_MASK) + pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL); + + if (im_protocols & NFC_PROTO_ISO14443_B_MASK) + pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B); + + if (tm_protocols) + pn533_poll_add_mod(dev, PN533_LISTEN_MOD); +} + +static int pn533_start_poll_complete(struct pn533 *dev, struct sk_buff *resp) +{ + u8 nbtg, tg, *tgdata; + int rc, tgdata_len; + + /* Toggle the DEP polling */ + if (dev->poll_protocols & NFC_PROTO_NFC_DEP_MASK) + dev->poll_dep = 1; + + nbtg = resp->data[0]; + tg = resp->data[1]; + tgdata = &resp->data[2]; + tgdata_len = resp->len - 2; /* nbtg + tg */ + + if (nbtg) { + rc = pn533_target_found(dev, tg, tgdata, tgdata_len); + + /* We must stop the poll after a valid target found */ + if (rc == 0) { + pn533_poll_reset_mod_list(dev); + return 0; + } + } + + return -EAGAIN; +} + +static struct sk_buff *pn533_alloc_poll_tg_frame(struct pn533 *dev) +{ + struct sk_buff *skb; + u8 *felica, *nfcid3, *gb; + + u8 *gbytes = dev->gb; + size_t gbytes_len = dev->gb_len; + + u8 felica_params[18] = {0x1, 0xfe, /* DEP */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff}; /* System code */ + + u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */ + 0x0, 0x0, 0x0, + 0x40}; /* SEL_RES for DEP */ + + unsigned int skb_len = 36 + /* + * mode (1), mifare (6), + * felica (18), nfcid3 (10), gb_len (1) + */ + gbytes_len + + 1; /* len Tk*/ + + skb = pn533_alloc_skb(dev, skb_len); + if (!skb) + return NULL; + + /* DEP support only */ + *skb_put(skb, 1) = PN533_INIT_TARGET_DEP; + + /* MIFARE params */ + memcpy(skb_put(skb, 6), mifare_params, 6); + + /* Felica params */ + felica = skb_put(skb, 18); + memcpy(felica, felica_params, 18); + get_random_bytes(felica + 2, 6); + + /* NFCID3 */ + nfcid3 = skb_put(skb, 10); + memset(nfcid3, 0, 10); + memcpy(nfcid3, felica, 8); + + /* General bytes */ + *skb_put(skb, 1) = gbytes_len; + + gb = skb_put(skb, gbytes_len); + memcpy(gb, gbytes, gbytes_len); + + /* Len Tk */ + *skb_put(skb, 1) = 0; + + return skb; +} + +static void pn533_wq_tm_mi_recv(struct work_struct *work); +static struct sk_buff *pn533_build_response(struct pn533 *dev); + +static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp) +{ + struct sk_buff *skb; + u8 status, ret, mi; + int rc; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (IS_ERR(resp)) { + skb_queue_purge(&dev->resp_q); + return PTR_ERR(resp); + } + + status = resp->data[0]; + + ret = status & PN533_CMD_RET_MASK; + mi = status & PN533_CMD_MI_MASK; + + skb_pull(resp, sizeof(status)); + + if (ret != PN533_CMD_RET_SUCCESS) { + rc = -EIO; + goto error; + } + + skb_queue_tail(&dev->resp_q, resp); + + if (mi) { + queue_work(dev->wq, &dev->mi_tm_rx_work); + return -EINPROGRESS; + } + + skb = pn533_build_response(dev); + if (!skb) { + rc = -EIO; + goto error; + } + + return nfc_tm_data_received(dev->nfc_dev, skb); + +error: + nfc_tm_deactivated(dev->nfc_dev); + dev->tgt_mode = 0; + skb_queue_purge(&dev->resp_q); + dev_kfree_skb(resp); + + return rc; +} + +static void pn533_wq_tm_mi_recv(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, mi_tm_rx_work); + struct sk_buff *skb; + int rc; + + dev_dbg(dev->dev, "%s\n", __func__); + + skb = pn533_alloc_skb(dev, 0); + if (!skb) + return; + + rc = pn533_send_cmd_direct_async(dev, + PN533_CMD_TG_GET_DATA, + skb, + pn533_tm_get_data_complete, + NULL); + + if (rc < 0) + dev_kfree_skb(skb); +} + +static int pn533_tm_send_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp); +static void pn533_wq_tm_mi_send(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, mi_tm_tx_work); + struct sk_buff *skb; + int rc; + + dev_dbg(dev->dev, "%s\n", __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; + } + + /* last entry - remove MI bit */ + if (skb_queue_len(&dev->fragment_skb) == 0) { + rc = pn533_send_cmd_direct_async(dev, PN533_CMD_TG_SET_DATA, + skb, pn533_tm_send_complete, NULL); + } else + rc = pn533_send_cmd_direct_async(dev, + PN533_CMD_TG_SET_META_DATA, + skb, pn533_tm_send_complete, NULL); + + if (rc == 0) /* success */ + return; + + dev_err(dev->dev, + "Error %d when trying to perform set meta data_exchange", rc); + + dev_kfree_skb(skb); + +error: + dev->phy_ops->send_ack(dev, GFP_KERNEL); + queue_work(dev->wq, &dev->cmd_work); +} + +static void pn533_wq_tg_get_data(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, tg_work); + struct sk_buff *skb; + int rc; + + dev_dbg(dev->dev, "%s\n", __func__); + + skb = pn533_alloc_skb(dev, 0); + if (!skb) + return; + + rc = pn533_send_data_async(dev, PN533_CMD_TG_GET_DATA, skb, + pn533_tm_get_data_complete, NULL); + + if (rc < 0) + dev_kfree_skb(skb); +} + +#define ATR_REQ_GB_OFFSET 17 +static int pn533_init_target_complete(struct pn533 *dev, struct sk_buff *resp) +{ + u8 mode, *cmd, comm_mode = NFC_COMM_PASSIVE, *gb; + size_t gb_len; + int rc; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (resp->len < ATR_REQ_GB_OFFSET + 1) + return -EINVAL; + + mode = resp->data[0]; + cmd = &resp->data[1]; + + dev_dbg(dev->dev, "Target mode 0x%x len %d\n", + mode, resp->len); + + if ((mode & PN533_INIT_TARGET_RESP_FRAME_MASK) == + PN533_INIT_TARGET_RESP_ACTIVE) + comm_mode = NFC_COMM_ACTIVE; + + if ((mode & PN533_INIT_TARGET_RESP_DEP) == 0) /* Only DEP supported */ + return -EOPNOTSUPP; + + gb = cmd + ATR_REQ_GB_OFFSET; + gb_len = resp->len - (ATR_REQ_GB_OFFSET + 1); + + rc = nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, + comm_mode, gb, gb_len); + if (rc < 0) { + nfc_err(dev->dev, + "Error when signaling target activation\n"); + return rc; + } + + dev->tgt_mode = 1; + queue_work(dev->wq, &dev->tg_work); + + return 0; +} + +static void pn533_listen_mode_timer(unsigned long data) +{ + struct pn533 *dev = (struct pn533 *)data; + + dev_dbg(dev->dev, "Listen mode timeout\n"); + + dev->cancel_listen = 1; + + pn533_poll_next_mod(dev); + + queue_delayed_work(dev->wq, &dev->poll_work, + msecs_to_jiffies(PN533_POLL_INTERVAL)); +} + +static int pn533_rf_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp) +{ + int rc = 0; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (IS_ERR(resp)) { + rc = PTR_ERR(resp); + + nfc_err(dev->dev, "RF setting error %d\n", rc); + + return rc; + } + + queue_delayed_work(dev->wq, &dev->poll_work, + msecs_to_jiffies(PN533_POLL_INTERVAL)); + + 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; + + dev_dbg(dev->dev, "%s\n", __func__); + + skb = pn533_alloc_skb(dev, 2); + if (!skb) + return; + + *skb_put(skb, 1) = PN533_CFGITEM_RF_FIELD; + *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); + if (rc < 0) { + dev_kfree_skb(skb); + nfc_err(dev->dev, "RF setting error %d\n", rc); + } +} + +static int pn533_poll_dep_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp) +{ + struct pn533_cmd_jump_dep_response *rsp; + struct nfc_target nfc_target; + u8 target_gt_len; + int rc; + + if (IS_ERR(resp)) + return PTR_ERR(resp); + + rsp = (struct pn533_cmd_jump_dep_response *)resp->data; + + rc = rsp->status & PN533_CMD_RET_MASK; + if (rc != PN533_CMD_RET_SUCCESS) { + /* Not target found, turn radio off */ + queue_work(dev->wq, &dev->rf_work); + + dev_kfree_skb(resp); + return 0; + } + + dev_dbg(dev->dev, "Creating new target"); + + nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK; + nfc_target.nfcid1_len = 10; + memcpy(nfc_target.nfcid1, rsp->nfcid3t, nfc_target.nfcid1_len); + rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1); + if (rc) + goto error; + + dev->tgt_available_prots = 0; + dev->tgt_active_prot = NFC_PROTO_NFC_DEP; + + /* ATR_RES general bytes are located at offset 17 */ + target_gt_len = resp->len - 17; + rc = nfc_set_remote_general_bytes(dev->nfc_dev, + rsp->gt, target_gt_len); + if (!rc) { + rc = nfc_dep_link_is_up(dev->nfc_dev, + dev->nfc_dev->targets[0].idx, + 0, NFC_RF_INITIATOR); + + if (!rc) + pn533_poll_reset_mod_list(dev); + } +error: + dev_kfree_skb(resp); + return rc; +} + +#define PASSIVE_DATA_LEN 5 +static int pn533_poll_dep(struct nfc_dev *nfc_dev) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + struct sk_buff *skb; + int rc, skb_len; + u8 *next, nfcid3[NFC_NFCID3_MAXSIZE]; + u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3}; + + dev_dbg(dev->dev, "%s", __func__); + + if (!dev->gb) { + dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len); + + if (!dev->gb || !dev->gb_len) { + dev->poll_dep = 0; + queue_work(dev->wq, &dev->rf_work); + } + } + + skb_len = 3 + dev->gb_len; /* ActPass + BR + Next */ + skb_len += PASSIVE_DATA_LEN; + + /* NFCID3 */ + skb_len += NFC_NFCID3_MAXSIZE; + 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) = 0x01; /* Active */ + *skb_put(skb, 1) = 0x02; /* 424 kbps */ + + next = skb_put(skb, 1); /* Next */ + *next = 0; + + /* Copy passive data */ + memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, PASSIVE_DATA_LEN); + *next |= 1; + + /* Copy NFCID3 (which is NFCID2 from SENSF_RES) */ + memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), nfcid3, + NFC_NFCID3_MAXSIZE); + *next |= 2; + + memcpy(skb_put(skb, dev->gb_len), dev->gb, dev->gb_len); + *next |= 4; /* We have some Gi */ + + rc = pn533_send_cmd_async(dev, PN533_CMD_IN_JUMP_FOR_DEP, skb, + pn533_poll_dep_complete, NULL); + + if (rc < 0) + dev_kfree_skb(skb); + + return rc; +} + +static int pn533_poll_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp) +{ + struct pn533_poll_modulations *cur_mod; + int rc; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (IS_ERR(resp)) { + rc = PTR_ERR(resp); + + nfc_err(dev->dev, "%s Poll complete error %d\n", + __func__, rc); + + if (rc == -ENOENT) { + if (dev->poll_mod_count != 0) + return rc; + goto stop_poll; + } else if (rc < 0) { + nfc_err(dev->dev, + "Error %d when running poll\n", rc); + goto stop_poll; + } + } + + cur_mod = dev->poll_mod_active[dev->poll_mod_curr]; + + if (cur_mod->len == 0) { /* Target mode */ + del_timer(&dev->listen_timer); + rc = pn533_init_target_complete(dev, resp); + goto done; + } + + /* Initiator mode */ + rc = pn533_start_poll_complete(dev, resp); + if (!rc) + goto done; + + if (!dev->poll_mod_count) { + dev_dbg(dev->dev, "Polling has been stopped\n"); + goto done; + } + + pn533_poll_next_mod(dev); + /* Not target found, turn radio off */ + queue_work(dev->wq, &dev->rf_work); + +done: + dev_kfree_skb(resp); + return rc; + +stop_poll: + nfc_err(dev->dev, "Polling operation has been stopped\n"); + + pn533_poll_reset_mod_list(dev); + dev->poll_protocols = 0; + return rc; +} + +static struct sk_buff *pn533_alloc_poll_in_frame(struct pn533 *dev, + struct pn533_poll_modulations *mod) +{ + struct sk_buff *skb; + + skb = pn533_alloc_skb(dev, mod->len); + if (!skb) + return NULL; + + memcpy(skb_put(skb, mod->len), &mod->data, mod->len); + + return skb; +} + +static int pn533_send_poll_frame(struct pn533 *dev) +{ + struct pn533_poll_modulations *mod; + struct sk_buff *skb; + int rc; + u8 cmd_code; + + mod = dev->poll_mod_active[dev->poll_mod_curr]; + + dev_dbg(dev->dev, "%s mod len %d\n", + __func__, mod->len); + + if ((dev->poll_protocols & NFC_PROTO_NFC_DEP_MASK) && dev->poll_dep) { + dev->poll_dep = 0; + return pn533_poll_dep(dev->nfc_dev); + } + + if (mod->len == 0) { /* Listen mode */ + cmd_code = PN533_CMD_TG_INIT_AS_TARGET; + skb = pn533_alloc_poll_tg_frame(dev); + } else { /* Polling mode */ + cmd_code = PN533_CMD_IN_LIST_PASSIVE_TARGET; + skb = pn533_alloc_poll_in_frame(dev, mod); + } + + if (!skb) { + nfc_err(dev->dev, "Failed to allocate skb\n"); + return -ENOMEM; + } + + rc = pn533_send_cmd_async(dev, cmd_code, skb, pn533_poll_complete, + NULL); + if (rc < 0) { + dev_kfree_skb(skb); + nfc_err(dev->dev, "Polling loop error %d\n", rc); + } + + return rc; +} + +static void pn533_wq_poll(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, poll_work.work); + struct pn533_poll_modulations *cur_mod; + int rc; + + cur_mod = dev->poll_mod_active[dev->poll_mod_curr]; + + dev_dbg(dev->dev, + "%s cancel_listen %d modulation len %d\n", + __func__, dev->cancel_listen, cur_mod->len); + + if (dev->cancel_listen == 1) { + dev->cancel_listen = 0; + dev->phy_ops->abort_cmd(dev, GFP_ATOMIC); + } + + rc = pn533_send_poll_frame(dev); + if (rc) + return; + + if (cur_mod->len == 0 && dev->poll_mod_count > 1) + mod_timer(&dev->listen_timer, jiffies + PN533_LISTEN_TIME * HZ); +} + +static int pn533_start_poll(struct nfc_dev *nfc_dev, + u32 im_protocols, u32 tm_protocols) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + struct pn533_poll_modulations *cur_mod; + u8 rand_mod; + int rc; + + dev_dbg(dev->dev, + "%s: im protocols 0x%x tm protocols 0x%x\n", + __func__, im_protocols, tm_protocols); + + if (dev->tgt_active_prot) { + nfc_err(dev->dev, + "Cannot poll with a target already activated\n"); + return -EBUSY; + } + + if (dev->tgt_mode) { + nfc_err(dev->dev, + "Cannot poll while already being activated\n"); + return -EBUSY; + } + + if (tm_protocols) { + dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len); + if (dev->gb == NULL) + tm_protocols = 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; + + cur_mod = dev->poll_mod_active[dev->poll_mod_curr]; + + rc = pn533_send_poll_frame(dev); + + /* Start listen timer */ + if (!rc && cur_mod->len == 0 && dev->poll_mod_count > 1) + mod_timer(&dev->listen_timer, jiffies + PN533_LISTEN_TIME * HZ); + + return rc; +} + +static void pn533_stop_poll(struct nfc_dev *nfc_dev) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + + del_timer(&dev->listen_timer); + + if (!dev->poll_mod_count) { + dev_dbg(dev->dev, + "Polling operation was not running\n"); + return; + } + + dev->phy_ops->abort_cmd(dev, GFP_KERNEL); + flush_delayed_work(&dev->poll_work); + pn533_poll_reset_mod_list(dev); +} + +static int pn533_activate_target_nfcdep(struct pn533 *dev) +{ + struct pn533_cmd_activate_response *rsp; + u16 gt_len; + int rc; + struct sk_buff *skb; + struct sk_buff *resp; + + dev_dbg(dev->dev, "%s\n", __func__); + + skb = pn533_alloc_skb(dev, sizeof(u8) * 2); /*TG + Next*/ + if (!skb) + return -ENOMEM; + + *skb_put(skb, sizeof(u8)) = 1; /* TG */ + *skb_put(skb, sizeof(u8)) = 0; /* Next */ + + resp = pn533_send_cmd_sync(dev, PN533_CMD_IN_ATR, skb); + if (IS_ERR(resp)) + return PTR_ERR(resp); + + rsp = (struct pn533_cmd_activate_response *)resp->data; + rc = rsp->status & PN533_CMD_RET_MASK; + if (rc != PN533_CMD_RET_SUCCESS) { + nfc_err(dev->dev, + "Target activation failed (error 0x%x)\n", rc); + dev_kfree_skb(resp); + return -EIO; + } + + /* ATR_RES general bytes are located at offset 16 */ + gt_len = resp->len - 16; + rc = nfc_set_remote_general_bytes(dev->nfc_dev, rsp->gt, gt_len); + + dev_kfree_skb(resp); + return rc; +} + +static int pn533_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, u32 protocol) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + int rc; + + dev_dbg(dev->dev, "%s: protocol=%u\n", __func__, protocol); + + if (dev->poll_mod_count) { + nfc_err(dev->dev, + "Cannot activate while polling\n"); + return -EBUSY; + } + + if (dev->tgt_active_prot) { + nfc_err(dev->dev, + "There is already an active target\n"); + return -EBUSY; + } + + if (!dev->tgt_available_prots) { + nfc_err(dev->dev, + "There is no available target to activate\n"); + return -EINVAL; + } + + if (!(dev->tgt_available_prots & (1 << protocol))) { + nfc_err(dev->dev, + "Target doesn't support requested proto %u\n", + protocol); + return -EINVAL; + } + + if (protocol == NFC_PROTO_NFC_DEP) { + rc = pn533_activate_target_nfcdep(dev); + if (rc) { + nfc_err(dev->dev, + "Activating target with DEP failed %d\n", rc); + return rc; + } + } + + dev->tgt_active_prot = protocol; + dev->tgt_available_prots = 0; + + return 0; +} + +static int pn533_deactivate_target_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp) +{ + int rc = 0; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (IS_ERR(resp)) { + rc = PTR_ERR(resp); + + nfc_err(dev->dev, "Target release error %d\n", rc); + + return rc; + } + + rc = resp->data[0] & PN533_CMD_RET_MASK; + if (rc != PN533_CMD_RET_SUCCESS) + nfc_err(dev->dev, + "Error 0x%x when releasing the target\n", rc); + + dev_kfree_skb(resp); + return rc; +} + +static void pn533_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, u8 mode) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + struct sk_buff *skb; + int rc; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (!dev->tgt_active_prot) { + nfc_err(dev->dev, "There is no active target\n"); + return; + } + + dev->tgt_active_prot = 0; + skb_queue_purge(&dev->resp_q); + + skb = pn533_alloc_skb(dev, sizeof(u8)); + if (!skb) + return; + + *skb_put(skb, 1) = 1; /* TG*/ + + rc = pn533_send_cmd_async(dev, PN533_CMD_IN_RELEASE, skb, + pn533_deactivate_target_complete, NULL); + if (rc < 0) { + dev_kfree_skb(skb); + nfc_err(dev->dev, "Target release error %d\n", rc); + } +} + + +static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp) +{ + struct pn533_cmd_jump_dep_response *rsp; + u8 target_gt_len; + int rc; + u8 active = *(u8 *)arg; + + kfree(arg); + + if (IS_ERR(resp)) + return PTR_ERR(resp); + + if (dev->tgt_available_prots && + !(dev->tgt_available_prots & (1 << NFC_PROTO_NFC_DEP))) { + nfc_err(dev->dev, + "The target does not support DEP\n"); + rc = -EINVAL; + goto error; + } + + rsp = (struct pn533_cmd_jump_dep_response *)resp->data; + + rc = rsp->status & PN533_CMD_RET_MASK; + if (rc != PN533_CMD_RET_SUCCESS) { + nfc_err(dev->dev, + "Bringing DEP link up failed (error 0x%x)\n", rc); + goto error; + } + + if (!dev->tgt_available_prots) { + struct nfc_target nfc_target; + + dev_dbg(dev->dev, "Creating new target\n"); + + nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK; + nfc_target.nfcid1_len = 10; + memcpy(nfc_target.nfcid1, rsp->nfcid3t, nfc_target.nfcid1_len); + rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1); + if (rc) + goto error; + + dev->tgt_available_prots = 0; + } + + dev->tgt_active_prot = NFC_PROTO_NFC_DEP; + + /* ATR_RES general bytes are located at offset 17 */ + target_gt_len = resp->len - 17; + rc = nfc_set_remote_general_bytes(dev->nfc_dev, + rsp->gt, target_gt_len); + if (rc == 0) + rc = nfc_dep_link_is_up(dev->nfc_dev, + dev->nfc_dev->targets[0].idx, + !active, NFC_RF_INITIATOR); + +error: + dev_kfree_skb(resp); + return rc; +} + +static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf); +static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, + u8 comm_mode, u8 *gb, size_t gb_len) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + struct sk_buff *skb; + int rc, skb_len; + u8 *next, *arg, nfcid3[NFC_NFCID3_MAXSIZE]; + u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3}; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (dev->poll_mod_count) { + nfc_err(dev->dev, + "Cannot bring the DEP link up while polling\n"); + return -EBUSY; + } + + if (dev->tgt_active_prot) { + nfc_err(dev->dev, + "There is already an active target\n"); + return -EBUSY; + } + + skb_len = 3 + gb_len; /* ActPass + BR + Next */ + skb_len += PASSIVE_DATA_LEN; + + /* 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) = 0x02; /* 424 kbps */ + + next = skb_put(skb, 1); /* Next */ + *next = 0; + + /* Copy passive data */ + memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data, PASSIVE_DATA_LEN); + *next |= 1; + + /* 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); + 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); + *next |= 4; /* We have some Gi */ + } else { + *next = 0; + } + + arg = kmalloc(sizeof(*arg), GFP_KERNEL); + if (!arg) { + dev_kfree_skb(skb); + return -ENOMEM; + } + + *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); + + if (rc < 0) { + dev_kfree_skb(skb); + kfree(arg); + } + + return rc; +} + +static int pn533_dep_link_down(struct nfc_dev *nfc_dev) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + + dev_dbg(dev->dev, "%s\n", __func__); + + pn533_poll_reset_mod_list(dev); + + if (dev->tgt_mode || dev->tgt_active_prot) + dev->phy_ops->abort_cmd(dev, GFP_KERNEL); + + dev->tgt_active_prot = 0; + dev->tgt_mode = 0; + + skb_queue_purge(&dev->resp_q); + + return 0; +} + +struct pn533_data_exchange_arg { + data_exchange_cb_t cb; + void *cb_context; +}; + +static struct sk_buff *pn533_build_response(struct pn533 *dev) +{ + struct sk_buff *skb, *tmp, *t; + unsigned int skb_len = 0, tmp_len = 0; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (skb_queue_empty(&dev->resp_q)) + return NULL; + + if (skb_queue_len(&dev->resp_q) == 1) { + skb = skb_dequeue(&dev->resp_q); + goto out; + } + + skb_queue_walk_safe(&dev->resp_q, tmp, t) + skb_len += tmp->len; + + dev_dbg(dev->dev, "%s total length %d\n", + __func__, skb_len); + + skb = alloc_skb(skb_len, GFP_KERNEL); + if (skb == NULL) + goto out; + + skb_put(skb, skb_len); + + skb_queue_walk_safe(&dev->resp_q, tmp, t) { + memcpy(skb->data + tmp_len, tmp->data, tmp->len); + tmp_len += tmp->len; + } + +out: + skb_queue_purge(&dev->resp_q); + + return skb; +} + +static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, + struct sk_buff *resp) +{ + struct pn533_data_exchange_arg *arg = _arg; + struct sk_buff *skb; + int rc = 0; + u8 status, ret, mi; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (IS_ERR(resp)) { + rc = PTR_ERR(resp); + goto _error; + } + + status = resp->data[0]; + ret = status & PN533_CMD_RET_MASK; + mi = status & PN533_CMD_MI_MASK; + + skb_pull(resp, sizeof(status)); + + if (ret != PN533_CMD_RET_SUCCESS) { + nfc_err(dev->dev, + "Exchanging data failed (error 0x%x)\n", ret); + rc = -EIO; + goto error; + } + + skb_queue_tail(&dev->resp_q, resp); + + if (mi) { + dev->cmd_complete_mi_arg = arg; + 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; + } + + skb = pn533_build_response(dev); + if (!skb) { + rc = -ENOMEM; + goto error; + } + + arg->cb(arg->cb_context, skb, 0); + kfree(arg); + return 0; + +error: + dev_kfree_skb(resp); +_error: + skb_queue_purge(&dev->resp_q); + arg->cb(arg->cb_context, NULL, rc); + kfree(arg); + return rc; +} + +/* + * Receive an incoming pn533 frame. skb contains only header and payload. + * If skb == NULL, it is a notification that the link below is dead. + */ +void pn533_recv_frame(struct pn533 *dev, struct sk_buff *skb, int status) +{ + dev->cmd->status = status; + + if (skb == NULL) { + pr_err("NULL Frame -> link is dead\n"); + goto sched_wq; + } + + if (pn533_rx_frame_is_ack(skb->data)) { + dev_dbg(dev->dev, "%s: Received ACK frame\n", __func__); + dev_kfree_skb(skb); + return; + } + + print_hex_dump_debug("PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, skb->data, + dev->ops->rx_frame_size(skb->data), false); + + if (!dev->ops->rx_is_frame_valid(skb->data, dev)) { + nfc_err(dev->dev, "Received an invalid frame\n"); + dev->cmd->status = -EIO; + } else if (!pn533_rx_frame_is_cmd_response(dev, skb->data)) { + nfc_err(dev->dev, "It it not the response to the last command\n"); + dev->cmd->status = -EIO; + } + + dev->cmd->resp = skb; + +sched_wq: + queue_work(dev->wq, &dev->cmd_complete_work); +} +EXPORT_SYMBOL(pn533_recv_frame); + +/* 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; + } + + if (!dev->tgt_mode) { + /* 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) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + struct pn533_data_exchange_arg *arg = NULL; + int rc; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (!dev->tgt_active_prot) { + nfc_err(dev->dev, + "Can't exchange data if there is no active target\n"); + rc = -EINVAL; + goto error; + } + + arg = kmalloc(sizeof(*arg), GFP_KERNEL); + if (!arg) { + rc = -ENOMEM; + goto error; + } + + arg->cb = cb; + arg->cb_context = cb_context; + + switch (dev->device_type) { + case PN533_DEVICE_PASORI: + if (dev->tgt_active_prot == NFC_PROTO_FELICA) { + rc = pn533_send_data_async(dev, PN533_CMD_IN_COMM_THRU, + skb, + pn533_data_exchange_complete, + arg); + + break; + } + default: + /* 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, + arg); + + break; + } + + if (rc < 0) /* rc from send_async */ + goto error; + + return 0; + +error: + kfree(arg); + dev_kfree_skb(skb); + return rc; +} + +static int pn533_tm_send_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp) +{ + u8 status; + + dev_dbg(dev->dev, "%s\n", __func__); + + if (IS_ERR(resp)) + return PTR_ERR(resp); + + status = resp->data[0]; + + /* Prepare for the next round */ + if (skb_queue_len(&dev->fragment_skb) > 0) { + queue_work(dev->wq, &dev->mi_tm_tx_work); + return -EINPROGRESS; + } + dev_kfree_skb(resp); + + if (status != 0) { + nfc_tm_deactivated(dev->nfc_dev); + + dev->tgt_mode = 0; + + return 0; + } + + queue_work(dev->wq, &dev->tg_work); + + return 0; +} + +static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + int rc; + + dev_dbg(dev->dev, "%s\n", __func__); + + /* let's split in multiple chunks if size's too big */ + if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) { + rc = pn533_fill_fragment_skbs(dev, skb); + if (rc <= 0) + goto error; + + /* get the first skb */ + skb = skb_dequeue(&dev->fragment_skb); + if (!skb) { + rc = -EIO; + goto error; + } + + rc = pn533_send_data_async(dev, PN533_CMD_TG_SET_META_DATA, skb, + pn533_tm_send_complete, NULL); + } else { + /* Send th skb */ + rc = pn533_send_data_async(dev, PN533_CMD_TG_SET_DATA, skb, + pn533_tm_send_complete, NULL); + } + +error: + if (rc < 0) { + dev_kfree_skb(skb); + skb_queue_purge(&dev->fragment_skb); + } + + return rc; +} + +static void pn533_wq_mi_recv(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, mi_rx_work); + struct sk_buff *skb; + int rc; + + dev_dbg(dev->dev, "%s\n", __func__); + + skb = pn533_alloc_skb(dev, PN533_CMD_DATAEXCH_HEAD_LEN); + if (!skb) + goto error; + + switch (dev->device_type) { + case PN533_DEVICE_PASORI: + if (dev->tgt_active_prot == NFC_PROTO_FELICA) { + rc = pn533_send_cmd_direct_async(dev, + PN533_CMD_IN_COMM_THRU, + skb, + pn533_data_exchange_complete, + dev->cmd_complete_mi_arg); + + break; + } + default: + *skb_put(skb, sizeof(u8)) = 1; /*TG*/ + + rc = pn533_send_cmd_direct_async(dev, + PN533_CMD_IN_DATA_EXCHANGE, + skb, + pn533_data_exchange_complete, + dev->cmd_complete_mi_arg); + + break; + } + + if (rc == 0) /* success */ + return; + + nfc_err(dev->dev, + "Error %d when trying to perform data_exchange\n", rc); + + dev_kfree_skb(skb); + kfree(dev->cmd_complete_mi_arg); + +error: + dev->phy_ops->send_ack(dev, GFP_KERNEL); + 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; + + dev_dbg(dev->dev, "%s\n", __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_err(dev->dev, + "Error %d when trying to perform data_exchange\n", rc); + + dev_kfree_skb(skb); + kfree(dev->cmd_complete_dep_arg); + +error: + dev->phy_ops->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) +{ + struct sk_buff *skb; + struct sk_buff *resp; + int skb_len; + + dev_dbg(dev->dev, "%s\n", __func__); + + skb_len = sizeof(cfgitem) + cfgdata_len; /* cfgitem + cfgdata */ + + skb = pn533_alloc_skb(dev, skb_len); + if (!skb) + return -ENOMEM; + + *skb_put(skb, sizeof(cfgitem)) = cfgitem; + memcpy(skb_put(skb, cfgdata_len), cfgdata, cfgdata_len); + + resp = pn533_send_cmd_sync(dev, PN533_CMD_RF_CONFIGURATION, skb); + if (IS_ERR(resp)) + return PTR_ERR(resp); + + dev_kfree_skb(resp); + return 0; +} + +static int pn533_get_firmware_version(struct pn533 *dev, + struct pn533_fw_version *fv) +{ + struct sk_buff *skb; + struct sk_buff *resp; + + skb = pn533_alloc_skb(dev, 0); + if (!skb) + return -ENOMEM; + + resp = pn533_send_cmd_sync(dev, PN533_CMD_GET_FIRMWARE_VERSION, skb); + if (IS_ERR(resp)) + return PTR_ERR(resp); + + fv->ic = resp->data[0]; + fv->ver = resp->data[1]; + fv->rev = resp->data[2]; + fv->support = resp->data[3]; + + dev_kfree_skb(resp); + return 0; +} + +static int pn533_pasori_fw_reset(struct pn533 *dev) +{ + struct sk_buff *skb; + struct sk_buff *resp; + + dev_dbg(dev->dev, "%s\n", __func__); + + skb = pn533_alloc_skb(dev, sizeof(u8)); + if (!skb) + return -ENOMEM; + + *skb_put(skb, sizeof(u8)) = 0x1; + + resp = pn533_send_cmd_sync(dev, 0x18, skb); + if (IS_ERR(resp)) + return PTR_ERR(resp); + + dev_kfree_skb(resp); + + return 0; +} + +static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + 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) { + nfc_err(dev->dev, "Error on setting RF field\n"); + return rc; + } + + return rc; +} + +static int pn533_dev_up(struct nfc_dev *nfc_dev) +{ + return pn533_rf_field(nfc_dev, 1); +} + +static int pn533_dev_down(struct nfc_dev *nfc_dev) +{ + return pn533_rf_field(nfc_dev, 0); +} + +static struct nfc_ops pn533_nfc_ops = { + .dev_up = pn533_dev_up, + .dev_down = pn533_dev_down, + .dep_link_up = pn533_dep_link_up, + .dep_link_down = pn533_dep_link_down, + .start_poll = pn533_start_poll, + .stop_poll = pn533_stop_poll, + .activate_target = pn533_activate_target, + .deactivate_target = pn533_deactivate_target, + .im_transceive = pn533_transceive, + .tm_send = pn533_tm_send, +}; + +static int pn533_setup(struct pn533 *dev) +{ + struct pn533_config_max_retries max_retries; + struct pn533_config_timing timing; + u8 pasori_cfg[3] = {0x08, 0x01, 0x08}; + int rc; + + switch (dev->device_type) { + case PN533_DEVICE_STD: + case PN533_DEVICE_PASORI: + case PN533_DEVICE_ACR122U: + max_retries.mx_rty_atr = 0x2; + max_retries.mx_rty_psl = 0x1; + 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_102; + timing.dep_timeout = PN533_CONFIG_TIMING_204; + + break; + + default: + nfc_err(dev->dev, "Unknown device type %d\n", + dev->device_type); + return -EINVAL; + } + + rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES, + (u8 *)&max_retries, sizeof(max_retries)); + if (rc) { + nfc_err(dev->dev, + "Error on setting MAX_RETRIES config\n"); + return rc; + } + + + rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING, + (u8 *)&timing, sizeof(timing)); + if (rc) { + nfc_err(dev->dev, "Error on setting RF timings\n"); + return rc; + } + + switch (dev->device_type) { + case PN533_DEVICE_STD: + break; + + case PN533_DEVICE_PASORI: + pn533_pasori_fw_reset(dev); + + rc = pn533_set_configuration(dev, PN533_CFGITEM_PASORI, + pasori_cfg, 3); + if (rc) { + nfc_err(dev->dev, + "Error while settings PASORI config\n"); + return rc; + } + + pn533_pasori_fw_reset(dev); + + break; + } + + return 0; +} + +struct pn533 *pn533_register_device(u32 device_type, + u32 protocols, + enum pn533_protocol_type protocol_type, + void *phy, + struct pn533_phy_ops *phy_ops, + struct pn533_frame_ops *fops, + struct device *dev) +{ + struct pn533_fw_version fw_ver; + struct pn533 *priv; + int rc = -ENOMEM; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return ERR_PTR(-ENOMEM); + + priv->phy = phy; + priv->phy_ops = phy_ops; + priv->dev = dev; + if (fops != NULL) + priv->ops = fops; + else + priv->ops = &pn533_std_frame_ops; + + priv->protocol_type = protocol_type; + priv->device_type = device_type; + + mutex_init(&priv->cmd_lock); + + INIT_WORK(&priv->cmd_work, pn533_wq_cmd); + INIT_WORK(&priv->cmd_complete_work, pn533_wq_cmd_complete); + INIT_WORK(&priv->mi_rx_work, pn533_wq_mi_recv); + INIT_WORK(&priv->mi_tx_work, pn533_wq_mi_send); + INIT_WORK(&priv->tg_work, pn533_wq_tg_get_data); + INIT_WORK(&priv->mi_tm_rx_work, pn533_wq_tm_mi_recv); + INIT_WORK(&priv->mi_tm_tx_work, pn533_wq_tm_mi_send); + INIT_DELAYED_WORK(&priv->poll_work, pn533_wq_poll); + INIT_WORK(&priv->rf_work, pn533_wq_rf); + priv->wq = alloc_ordered_workqueue("pn533", 0); + if (priv->wq == NULL) + goto error; + + init_timer(&priv->listen_timer); + priv->listen_timer.data = (unsigned long) priv; + priv->listen_timer.function = pn533_listen_mode_timer; + + skb_queue_head_init(&priv->resp_q); + skb_queue_head_init(&priv->fragment_skb); + + INIT_LIST_HEAD(&priv->cmd_queue); + + memset(&fw_ver, 0, sizeof(fw_ver)); + rc = pn533_get_firmware_version(priv, &fw_ver); + if (rc < 0) + goto destroy_wq; + + nfc_info(dev, "NXP PN5%02X firmware ver %d.%d now attached\n", + fw_ver.ic, fw_ver.ver, fw_ver.rev); + + + priv->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols, + priv->ops->tx_header_len + + PN533_CMD_DATAEXCH_HEAD_LEN, + priv->ops->tx_tail_len); + if (!priv->nfc_dev) { + rc = -ENOMEM; + goto destroy_wq; + } + + nfc_set_drvdata(priv->nfc_dev, priv); + + rc = nfc_register_device(priv->nfc_dev); + if (rc) + goto free_nfc_dev; + + rc = pn533_setup(priv); + if (rc) + goto unregister_nfc_dev; + + return priv; + +unregister_nfc_dev: + nfc_unregister_device(priv->nfc_dev); + +free_nfc_dev: + nfc_free_device(priv->nfc_dev); + +destroy_wq: + destroy_workqueue(priv->wq); +error: + kfree(priv); + return ERR_PTR(rc); +} +EXPORT_SYMBOL_GPL(pn533_register_device); + +void pn533_unregister_device(struct pn533 *priv) +{ + struct pn533_cmd *cmd, *n; + + nfc_unregister_device(priv->nfc_dev); + nfc_free_device(priv->nfc_dev); + + flush_delayed_work(&priv->poll_work); + destroy_workqueue(priv->wq); + + skb_queue_purge(&priv->resp_q); + + del_timer(&priv->listen_timer); + + list_for_each_entry_safe(cmd, n, &priv->cmd_queue, queue) { + list_del(&cmd->queue); + kfree(cmd); + } + + kfree(priv); +} +EXPORT_SYMBOL_GPL(pn533_unregister_device); + + +MODULE_AUTHOR("Lauro Ramos Venancio "); +MODULE_AUTHOR("Aloisio Almeida Jr "); +MODULE_AUTHOR("Waldemar Rymarkiewicz "); +MODULE_DESCRIPTION("PN533 driver ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/nfc/pn533/pn533.h b/drivers/nfc/pn533/pn533.h new file mode 100644 index 000000000000..1d9f19eb2a99 --- /dev/null +++ b/drivers/nfc/pn533/pn533.h @@ -0,0 +1,235 @@ +/* + * Driver for NXP PN533 NFC Chip + * + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * Copyright (C) 2012-2013 Tieto Poland + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#define PN533_DEVICE_STD 0x1 +#define PN533_DEVICE_PASORI 0x2 +#define PN533_DEVICE_ACR122U 0x3 + +#define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ + NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ + NFC_PROTO_NFC_DEP_MASK |\ + NFC_PROTO_ISO14443_B_MASK) + +#define PN533_NO_TYPE_B_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ + NFC_PROTO_MIFARE_MASK | \ + NFC_PROTO_FELICA_MASK | \ + NFC_PROTO_ISO14443_MASK | \ + NFC_PROTO_NFC_DEP_MASK) + +/* 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_HEAD_LEN 1 +#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. + */ +#define PN533_STD_FRAME_MAX_PAYLOAD_LEN 263 + + +/* Preamble (1), SoPC (2), ACK Code (2), Postamble (1) */ +#define PN533_STD_FRAME_ACK_SIZE 6 +#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 + +/* standard frame identifier: in/out/error */ +#define PN533_STD_FRAME_IDENTIFIER(f) (f->data[0]) /* TFI */ +#define PN533_STD_FRAME_DIR_OUT 0xD4 +#define PN533_STD_FRAME_DIR_IN 0xD5 + +/* PN533 Commands */ +#define PN533_FRAME_CMD(f) (f->data[1]) + +#define PN533_CMD_GET_FIRMWARE_VERSION 0x02 +#define PN533_CMD_RF_CONFIGURATION 0x32 +#define PN533_CMD_IN_DATA_EXCHANGE 0x40 +#define PN533_CMD_IN_COMM_THRU 0x42 +#define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A +#define PN533_CMD_IN_ATR 0x50 +#define PN533_CMD_IN_RELEASE 0x52 +#define PN533_CMD_IN_JUMP_FOR_DEP 0x56 + +#define PN533_CMD_TG_INIT_AS_TARGET 0x8c +#define PN533_CMD_TG_GET_DATA 0x86 +#define PN533_CMD_TG_SET_DATA 0x8e +#define PN533_CMD_TG_SET_META_DATA 0x94 +#define PN533_CMD_UNDEF 0xff + +#define PN533_CMD_RESPONSE(cmd) (cmd + 1) + +/* PN533 Return codes */ +#define PN533_CMD_RET_MASK 0x3F +#define PN533_CMD_MI_MASK 0x40 +#define PN533_CMD_RET_SUCCESS 0x00 + + +enum pn533_protocol_type { + PN533_PROTO_REQ_ACK_RESP = 0, + PN533_PROTO_REQ_RESP +}; + +/* Poll modulations */ +enum { + PN533_POLL_MOD_106KBPS_A, + PN533_POLL_MOD_212KBPS_FELICA, + PN533_POLL_MOD_424KBPS_FELICA, + PN533_POLL_MOD_106KBPS_JEWEL, + PN533_POLL_MOD_847KBPS_B, + PN533_LISTEN_MOD, + + __PN533_POLL_MOD_AFTER_LAST, +}; +#define PN533_POLL_MOD_MAX (__PN533_POLL_MOD_AFTER_LAST - 1) + +struct pn533_std_frame { + u8 preamble; + __be16 start_frame; + u8 datalen; + u8 datalen_checksum; + 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 { + struct nfc_dev *nfc_dev; + u32 device_type; + enum pn533_protocol_type protocol_type; + + 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 delayed_work poll_work; + struct work_struct mi_rx_work; + struct work_struct mi_tx_work; + struct work_struct mi_tm_rx_work; + struct work_struct mi_tm_tx_work; + struct work_struct tg_work; + struct work_struct rf_work; + + struct list_head cmd_queue; + struct pn533_cmd *cmd; + u8 cmd_pending; + 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; + u8 poll_mod_curr; + u8 poll_dep; + u32 poll_protocols; + u32 listen_protocols; + struct timer_list listen_timer; + int cancel_listen; + + u8 *gb; + size_t gb_len; + + u8 tgt_available_prots; + u8 tgt_active_prot; + u8 tgt_mode; + + struct pn533_frame_ops *ops; + + struct device *dev; + void *phy; + struct pn533_phy_ops *phy_ops; +}; + +typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg, + struct sk_buff *resp); + +struct pn533_cmd { + struct list_head queue; + u8 code; + int status; + struct sk_buff *req; + struct sk_buff *resp; + pn533_send_async_complete_t complete_cb; + void *complete_cb_context; +}; + + +struct pn533_frame_ops { + void (*tx_frame_init)(void *frame, u8 cmd_code); + void (*tx_frame_finish)(void *frame); + void (*tx_update_payload_len)(void *frame, int len); + int tx_header_len; + int tx_tail_len; + + bool (*rx_is_frame_valid)(void *frame, struct pn533 *dev); + bool (*rx_frame_is_ack)(void *frame); + int (*rx_frame_size)(void *frame); + int rx_header_len; + int rx_tail_len; + + int max_payload_len; + u8 (*get_cmd_code)(void *frame); +}; + + +struct pn533_phy_ops { + int (*send_frame)(struct pn533 *priv, + struct sk_buff *out); + int (*send_ack)(struct pn533 *dev, gfp_t flags); + void (*abort_cmd)(struct pn533 *priv, gfp_t flags); +}; + + +struct pn533 *pn533_register_device(u32 device_type, + u32 protocols, + enum pn533_protocol_type protocol_type, + void *phy, + struct pn533_phy_ops *phy_ops, + struct pn533_frame_ops *fops, + struct device *dev); + +void pn533_unregister_device(struct pn533 *priv); +void pn533_recv_frame(struct pn533 *dev, struct sk_buff *skb, int status); + +bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame); +bool pn533_rx_frame_is_ack(void *_frame); diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c new file mode 100644 index 000000000000..4f73cbf8ccef --- /dev/null +++ b/drivers/nfc/pn533/usb.c @@ -0,0 +1,598 @@ +/* + * Driver for NXP PN533 NFC Chip - USB transport layer + * + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * Copyright (C) 2012-2013 Tieto Poland + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pn533.h" + +#define VERSION "0.1" + +#define PN533_VENDOR_ID 0x4CC +#define PN533_PRODUCT_ID 0x2533 + +#define SCM_VENDOR_ID 0x4E6 +#define SCL3711_PRODUCT_ID 0x5591 + +#define SONY_VENDOR_ID 0x054c +#define PASORI_PRODUCT_ID 0x02e1 + +#define ACS_VENDOR_ID 0x072f +#define ACR122U_PRODUCT_ID 0x2200 + +static const struct usb_device_id pn533_usb_table[] = { + { USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID), + .driver_info = PN533_DEVICE_STD }, + { USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID), + .driver_info = PN533_DEVICE_STD }, + { USB_DEVICE(SONY_VENDOR_ID, PASORI_PRODUCT_ID), + .driver_info = PN533_DEVICE_PASORI }, + { USB_DEVICE(ACS_VENDOR_ID, ACR122U_PRODUCT_ID), + .driver_info = PN533_DEVICE_ACR122U }, + { } +}; +MODULE_DEVICE_TABLE(usb, pn533_usb_table); + +struct pn533_usb_phy { + struct usb_device *udev; + struct usb_interface *interface; + + struct urb *out_urb; + struct urb *in_urb; + + struct pn533 *priv; +}; + +static void pn533_recv_response(struct urb *urb) +{ + struct pn533_usb_phy *phy = urb->context; + struct sk_buff *skb = NULL; + + if (!urb->status) { + skb = alloc_skb(urb->actual_length, GFP_KERNEL); + if (!skb) { + nfc_err(&phy->udev->dev, "failed to alloc memory\n"); + } else { + memcpy(skb_put(skb, urb->actual_length), + urb->transfer_buffer, urb->actual_length); + } + } + + pn533_recv_frame(phy->priv, skb, urb->status); +} + +static int pn533_submit_urb_for_response(struct pn533_usb_phy *phy, gfp_t flags) +{ + phy->in_urb->complete = pn533_recv_response; + + return usb_submit_urb(phy->in_urb, flags); +} + +static void pn533_recv_ack(struct urb *urb) +{ + struct pn533_usb_phy *phy = urb->context; + struct pn533 *priv = phy->priv; + struct pn533_cmd *cmd = priv->cmd; + struct pn533_std_frame *in_frame; + int rc; + + cmd->status = urb->status; + + switch (urb->status) { + case 0: + break; /* success */ + case -ECONNRESET: + case -ENOENT: + dev_dbg(&phy->udev->dev, + "The urb has been stopped (status %d)\n", + urb->status); + goto sched_wq; + case -ESHUTDOWN: + default: + nfc_err(&phy->udev->dev, + "Urb failure (status %d)\n", urb->status); + goto sched_wq; + } + + in_frame = phy->in_urb->transfer_buffer; + + if (!pn533_rx_frame_is_ack(in_frame)) { + nfc_err(&phy->udev->dev, "Received an invalid ack\n"); + cmd->status = -EIO; + goto sched_wq; + } + + rc = pn533_submit_urb_for_response(phy, GFP_ATOMIC); + if (rc) { + nfc_err(&phy->udev->dev, + "usb_submit_urb failed with result %d\n", rc); + cmd->status = rc; + goto sched_wq; + } + + return; + +sched_wq: + queue_work(priv->wq, &priv->cmd_complete_work); +} + +static int pn533_submit_urb_for_ack(struct pn533_usb_phy *phy, gfp_t flags) +{ + phy->in_urb->complete = pn533_recv_ack; + + return usb_submit_urb(phy->in_urb, flags); +} + +static int pn533_usb_send_ack(struct pn533 *dev, gfp_t flags) +{ + struct pn533_usb_phy *phy = dev->phy; + u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; + /* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */ + int rc; + + phy->out_urb->transfer_buffer = ack; + phy->out_urb->transfer_buffer_length = sizeof(ack); + rc = usb_submit_urb(phy->out_urb, flags); + + return rc; +} + +static int pn533_usb_send_frame(struct pn533 *dev, + struct sk_buff *out) +{ + struct pn533_usb_phy *phy = dev->phy; + int rc; + + if (phy->priv == NULL) + phy->priv = dev; + + phy->out_urb->transfer_buffer = out->data; + phy->out_urb->transfer_buffer_length = out->len; + + print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1, + out->data, out->len, false); + + rc = usb_submit_urb(phy->out_urb, GFP_KERNEL); + if (rc) + return rc; + + if (dev->protocol_type == PN533_PROTO_REQ_RESP) { + /* request for response for sent packet directly */ + rc = pn533_submit_urb_for_response(phy, GFP_ATOMIC); + if (rc) + goto error; + } else if (dev->protocol_type == PN533_PROTO_REQ_ACK_RESP) { + /* request for ACK if that's the case */ + rc = pn533_submit_urb_for_ack(phy, GFP_KERNEL); + if (rc) + goto error; + } + + return 0; + +error: + usb_unlink_urb(phy->out_urb); + return rc; +} + +static void pn533_usb_abort_cmd(struct pn533 *dev, gfp_t flags) +{ + struct pn533_usb_phy *phy = dev->phy; + + /* ACR122U does not support any command which aborts last + * issued command i.e. as ACK for standard PN533. Additionally, + * it behaves stange, sending broken or incorrect responses, + * when we cancel urb before the chip will send response. + */ + if (dev->device_type == PN533_DEVICE_ACR122U) + return; + + /* An ack will cancel the last issued command */ + pn533_usb_send_ack(dev, flags); + + /* cancel the urb request */ + usb_kill_urb(phy->in_urb); +} + +/* ACR122 specific structs and fucntions */ + +/* ACS ACR122 pn533 frame definitions */ +#define PN533_ACR122_TX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_tx_frame) \ + + 2) +#define PN533_ACR122_TX_FRAME_TAIL_LEN 0 +#define PN533_ACR122_RX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_rx_frame) \ + + 2) +#define PN533_ACR122_RX_FRAME_TAIL_LEN 2 +#define PN533_ACR122_FRAME_MAX_PAYLOAD_LEN PN533_STD_FRAME_MAX_PAYLOAD_LEN + +/* CCID messages types */ +#define PN533_ACR122_PC_TO_RDR_ICCPOWERON 0x62 +#define PN533_ACR122_PC_TO_RDR_ESCAPE 0x6B + +#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83 + + +struct pn533_acr122_ccid_hdr { + u8 type; + u32 datalen; + u8 slot; + u8 seq; + + /* + * 3 msg specific bytes or status, error and 1 specific + * byte for reposnse msg + */ + u8 params[3]; + u8 data[]; /* payload */ +} __packed; + +struct pn533_acr122_apdu_hdr { + u8 class; + u8 ins; + u8 p1; + u8 p2; +} __packed; + +struct pn533_acr122_tx_frame { + struct pn533_acr122_ccid_hdr ccid; + struct pn533_acr122_apdu_hdr apdu; + u8 datalen; + u8 data[]; /* pn533 frame: TFI ... */ +} __packed; + +struct pn533_acr122_rx_frame { + struct pn533_acr122_ccid_hdr ccid; + u8 data[]; /* pn533 frame : TFI ... */ +} __packed; + +static void pn533_acr122_tx_frame_init(void *_frame, u8 cmd_code) +{ + struct pn533_acr122_tx_frame *frame = _frame; + + frame->ccid.type = PN533_ACR122_PC_TO_RDR_ESCAPE; + /* sizeof(apdu_hdr) + sizeof(datalen) */ + frame->ccid.datalen = sizeof(frame->apdu) + 1; + frame->ccid.slot = 0; + frame->ccid.seq = 0; + frame->ccid.params[0] = 0; + frame->ccid.params[1] = 0; + frame->ccid.params[2] = 0; + + frame->data[0] = PN533_STD_FRAME_DIR_OUT; + frame->data[1] = cmd_code; + frame->datalen = 2; /* data[0] + data[1] */ + + frame->apdu.class = 0xFF; + frame->apdu.ins = 0; + frame->apdu.p1 = 0; + frame->apdu.p2 = 0; +} + +static void pn533_acr122_tx_frame_finish(void *_frame) +{ + struct pn533_acr122_tx_frame *frame = _frame; + + frame->ccid.datalen += frame->datalen; +} + +static void pn533_acr122_tx_update_payload_len(void *_frame, int len) +{ + struct pn533_acr122_tx_frame *frame = _frame; + + frame->datalen += len; +} + +static bool pn533_acr122_is_rx_frame_valid(void *_frame, struct pn533 *dev) +{ + struct pn533_acr122_rx_frame *frame = _frame; + + if (frame->ccid.type != 0x83) + return false; + + if (!frame->ccid.datalen) + return false; + + if (frame->data[frame->ccid.datalen - 2] == 0x63) + return false; + + return true; +} + +static int pn533_acr122_rx_frame_size(void *frame) +{ + struct pn533_acr122_rx_frame *f = frame; + + /* f->ccid.datalen already includes tail length */ + return sizeof(struct pn533_acr122_rx_frame) + f->ccid.datalen; +} + +static u8 pn533_acr122_get_cmd_code(void *frame) +{ + struct pn533_acr122_rx_frame *f = frame; + + return PN533_FRAME_CMD(f); +} + +static struct pn533_frame_ops pn533_acr122_frame_ops = { + .tx_frame_init = pn533_acr122_tx_frame_init, + .tx_frame_finish = pn533_acr122_tx_frame_finish, + .tx_update_payload_len = pn533_acr122_tx_update_payload_len, + .tx_header_len = PN533_ACR122_TX_FRAME_HEADER_LEN, + .tx_tail_len = PN533_ACR122_TX_FRAME_TAIL_LEN, + + .rx_is_frame_valid = pn533_acr122_is_rx_frame_valid, + .rx_header_len = PN533_ACR122_RX_FRAME_HEADER_LEN, + .rx_tail_len = PN533_ACR122_RX_FRAME_TAIL_LEN, + .rx_frame_size = pn533_acr122_rx_frame_size, + + .max_payload_len = PN533_ACR122_FRAME_MAX_PAYLOAD_LEN, + .get_cmd_code = pn533_acr122_get_cmd_code, +}; + +struct pn533_acr122_poweron_rdr_arg { + int rc; + struct completion done; +}; + +static void pn533_acr122_poweron_rdr_resp(struct urb *urb) +{ + struct pn533_acr122_poweron_rdr_arg *arg = urb->context; + + dev_dbg(&urb->dev->dev, "%s\n", __func__); + + print_hex_dump_debug("ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1, + urb->transfer_buffer, urb->transfer_buffer_length, + false); + + arg->rc = urb->status; + complete(&arg->done); +} + +static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy) +{ + /* Power on th reader (CCID cmd) */ + u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON, + 0, 0, 0, 0, 0, 0, 3, 0, 0}; + int rc; + void *cntx; + struct pn533_acr122_poweron_rdr_arg arg; + + dev_dbg(&phy->udev->dev, "%s\n", __func__); + + init_completion(&arg.done); + cntx = phy->in_urb->context; /* backup context */ + + phy->in_urb->complete = pn533_acr122_poweron_rdr_resp; + phy->in_urb->context = &arg; + + phy->out_urb->transfer_buffer = cmd; + phy->out_urb->transfer_buffer_length = sizeof(cmd); + + print_hex_dump_debug("ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1, + cmd, sizeof(cmd), false); + + rc = usb_submit_urb(phy->out_urb, GFP_KERNEL); + if (rc) { + nfc_err(&phy->udev->dev, + "Reader power on cmd error %d\n", rc); + return rc; + } + + rc = usb_submit_urb(phy->in_urb, GFP_KERNEL); + if (rc) { + nfc_err(&phy->udev->dev, + "Can't submit reader poweron cmd response %d\n", rc); + return rc; + } + + wait_for_completion(&arg.done); + phy->in_urb->context = cntx; /* restore context */ + + return arg.rc; +} + +static void pn533_send_complete(struct urb *urb) +{ + struct pn533_usb_phy *phy = urb->context; + + switch (urb->status) { + case 0: + break; /* success */ + case -ECONNRESET: + case -ENOENT: + dev_dbg(&phy->udev->dev, + "The urb has been stopped (status %d)\n", + urb->status); + break; + case -ESHUTDOWN: + default: + nfc_err(&phy->udev->dev, + "Urb failure (status %d)\n", + urb->status); + } +} + +static struct pn533_phy_ops usb_phy_ops = { + .send_frame = pn533_usb_send_frame, + .send_ack = pn533_usb_send_ack, + .abort_cmd = pn533_usb_abort_cmd, +}; + +static int pn533_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct pn533 *priv; + struct pn533_usb_phy *phy; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int in_endpoint = 0; + int out_endpoint = 0; + int rc = -ENOMEM; + int i; + u32 protocols; + enum pn533_protocol_type protocol_type = PN533_PROTO_REQ_ACK_RESP; + struct pn533_frame_ops *fops = NULL; + unsigned char *in_buf; + int in_buf_len = PN533_EXT_FRAME_HEADER_LEN + + PN533_STD_FRAME_MAX_PAYLOAD_LEN + + PN533_STD_FRAME_TAIL_LEN; + + phy = devm_kzalloc(&interface->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + in_buf = kzalloc(in_buf_len, GFP_KERNEL); + if (!in_buf) { + rc = -ENOMEM; + goto out_free_phy; + } + + phy->udev = usb_get_dev(interface_to_usbdev(interface)); + phy->interface = interface; + + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint)) + in_endpoint = endpoint->bEndpointAddress; + + if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint)) + out_endpoint = endpoint->bEndpointAddress; + } + + if (!in_endpoint || !out_endpoint) { + nfc_err(&interface->dev, + "Could not find bulk-in or bulk-out endpoint\n"); + rc = -ENODEV; + goto error; + } + + phy->in_urb = usb_alloc_urb(0, GFP_KERNEL); + phy->out_urb = usb_alloc_urb(0, GFP_KERNEL); + + if (!phy->in_urb || !phy->out_urb) + goto error; + + usb_fill_bulk_urb(phy->in_urb, phy->udev, + usb_rcvbulkpipe(phy->udev, in_endpoint), + in_buf, in_buf_len, NULL, phy); + + usb_fill_bulk_urb(phy->out_urb, phy->udev, + usb_sndbulkpipe(phy->udev, out_endpoint), + NULL, 0, pn533_send_complete, phy); + + + switch (id->driver_info) { + case PN533_DEVICE_STD: + protocols = PN533_ALL_PROTOCOLS; + break; + + case PN533_DEVICE_PASORI: + protocols = PN533_NO_TYPE_B_PROTOCOLS; + break; + + case PN533_DEVICE_ACR122U: + protocols = PN533_NO_TYPE_B_PROTOCOLS; + fops = &pn533_acr122_frame_ops; + protocol_type = PN533_PROTO_REQ_RESP, + + rc = pn533_acr122_poweron_rdr(phy); + if (rc < 0) { + nfc_err(&interface->dev, + "Couldn't poweron the reader (error %d)\n", rc); + goto error; + } + break; + + default: + nfc_err(&interface->dev, "Unknown device type %lu\n", + id->driver_info); + rc = -EINVAL; + goto error; + } + + priv = pn533_register_device(id->driver_info, protocols, protocol_type, + phy, &usb_phy_ops, fops, + &phy->udev->dev); + + if (IS_ERR(priv)) { + rc = PTR_ERR(priv); + goto error; + } + + phy->priv = priv; + nfc_set_parent_dev(priv->nfc_dev, &interface->dev); + + usb_set_intfdata(interface, phy); + + return 0; + +error: + usb_free_urb(phy->in_urb); + usb_free_urb(phy->out_urb); + usb_put_dev(phy->udev); + kfree(in_buf); +out_free_phy: + kfree(phy); + return rc; +} + +static void pn533_usb_disconnect(struct usb_interface *interface) +{ + struct pn533_usb_phy *phy = usb_get_intfdata(interface); + + if (!phy) + return; + + pn533_unregister_device(phy->priv); + + usb_set_intfdata(interface, NULL); + + usb_kill_urb(phy->in_urb); + usb_kill_urb(phy->out_urb); + + kfree(phy->in_urb->transfer_buffer); + usb_free_urb(phy->in_urb); + usb_free_urb(phy->out_urb); + + nfc_info(&interface->dev, "NXP PN533 NFC device disconnected\n"); +} + +static struct usb_driver pn533_usb_driver = { + .name = "pn533_usb", + .probe = pn533_usb_probe, + .disconnect = pn533_usb_disconnect, + .id_table = pn533_usb_table, +}; + +module_usb_driver(pn533_usb_driver); + +MODULE_AUTHOR("Lauro Ramos Venancio "); +MODULE_AUTHOR("Aloisio Almeida Jr "); +MODULE_AUTHOR("Waldemar Rymarkiewicz "); +MODULE_DESCRIPTION("PN533 USB driver ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From dd7bedcd2673e4c8957d15d7e6e649fc6fa40206 Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Fri, 25 Mar 2016 15:46:54 +0100 Subject: NFC: pn533: add I2C phy driver This adds the I2C phy interface for the pn533 driver. This way the driver can be used to interact with I2C connected pn532 devices. Signed-off-by: Michael Thalmeier Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533/Kconfig | 11 ++ drivers/nfc/pn533/Makefile | 2 + drivers/nfc/pn533/i2c.c | 271 +++++++++++++++++++++++++++++++++++++++++++++ drivers/nfc/pn533/pn533.c | 31 ++++++ drivers/nfc/pn533/pn533.h | 2 + 5 files changed, 317 insertions(+) create mode 100644 drivers/nfc/pn533/i2c.c diff --git a/drivers/nfc/pn533/Kconfig b/drivers/nfc/pn533/Kconfig index b5a926e42f7b..d94122dd30e4 100644 --- a/drivers/nfc/pn533/Kconfig +++ b/drivers/nfc/pn533/Kconfig @@ -14,3 +14,14 @@ config NFC_PN533_USB If you choose to build a module, it'll be called pn533_usb. Say N if unsure. + +config NFC_PN533_I2C + tristate "NFC PN533 device support (I2C)" + depends on I2C + select NFC_PN533 + ---help--- + This module adds support for the NXP pn533 I2C interface. + Select this if your platform is using the I2C bus. + + If you choose to build a module, it'll be called pn533_i2c. + Say N if unsure. diff --git a/drivers/nfc/pn533/Makefile b/drivers/nfc/pn533/Makefile index 12c6be481483..51d24c622fcb 100644 --- a/drivers/nfc/pn533/Makefile +++ b/drivers/nfc/pn533/Makefile @@ -2,6 +2,8 @@ # Makefile for PN533 NFC driver # pn533_usb-objs = usb.o +pn533_i2c-objs = i2c.o obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_PN533_USB) += pn533_usb.o +obj-$(CONFIG_NFC_PN533_I2C) += pn533_i2c.o diff --git a/drivers/nfc/pn533/i2c.c b/drivers/nfc/pn533/i2c.c new file mode 100644 index 000000000000..9679aa52c381 --- /dev/null +++ b/drivers/nfc/pn533/i2c.c @@ -0,0 +1,271 @@ +/* + * Driver for NXP PN533 NFC Chip - I2C transport layer + * + * Copyright (C) 2011 Instituto Nokia de Tecnologia + * Copyright (C) 2012-2013 Tieto Poland + * Copyright (C) 2016 HALE electronic + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pn533.h" + +#define VERSION "0.1" + +#define PN533_I2C_DRIVER_NAME "pn533_i2c" + +struct pn533_i2c_phy { + struct i2c_client *i2c_dev; + struct pn533 *priv; + + int hard_fault; /* + * < 0 if hardware error occurred (e.g. i2c err) + * and prevents normal operation. + */ +}; + +static int pn533_i2c_send_ack(struct pn533 *dev, gfp_t flags) +{ + struct pn533_i2c_phy *phy = dev->phy; + struct i2c_client *client = phy->i2c_dev; + u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; + /* spec 6.2.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */ + int rc; + + rc = i2c_master_send(client, ack, 6); + + return rc; +} + +static int pn533_i2c_send_frame(struct pn533 *dev, + struct sk_buff *out) +{ + struct pn533_i2c_phy *phy = dev->phy; + struct i2c_client *client = phy->i2c_dev; + int rc; + + if (phy->hard_fault != 0) + return phy->hard_fault; + + if (phy->priv == NULL) + phy->priv = dev; + + print_hex_dump_debug("PN533_i2c TX: ", DUMP_PREFIX_NONE, 16, 1, + out->data, out->len, false); + + rc = i2c_master_send(client, out->data, out->len); + + if (rc == -EREMOTEIO) { /* Retry, chip was in power down */ + usleep_range(6000, 10000); + rc = i2c_master_send(client, out->data, out->len); + } + + if (rc >= 0) { + if (rc != out->len) + rc = -EREMOTEIO; + else + rc = 0; + } + + return rc; +} + +static void pn533_i2c_abort_cmd(struct pn533 *dev, gfp_t flags) +{ + /* An ack will cancel the last issued command */ + pn533_i2c_send_ack(dev, flags); + + /* schedule cmd_complete_work to finish current command execution */ + if (dev->cmd != NULL) + dev->cmd->status = -ENOENT; + queue_work(dev->wq, &dev->cmd_complete_work); +} + +static int pn533_i2c_read(struct pn533_i2c_phy *phy, struct sk_buff **skb) +{ + struct i2c_client *client = phy->i2c_dev; + int len = PN533_EXT_FRAME_HEADER_LEN + + PN533_STD_FRAME_MAX_PAYLOAD_LEN + + PN533_STD_FRAME_TAIL_LEN + 1; + int r; + + *skb = alloc_skb(len, GFP_KERNEL); + if (*skb == NULL) + return -ENOMEM; + + r = i2c_master_recv(client, skb_put(*skb, len), len); + if (r != len) { + nfc_err(&client->dev, "cannot read. r=%d len=%d\n", r, len); + kfree_skb(*skb); + return -EREMOTEIO; + } + + if (!((*skb)->data[0] & 0x01)) { + nfc_err(&client->dev, "READY flag not set"); + kfree_skb(*skb); + return -EBUSY; + } + + /* remove READY byte */ + skb_pull(*skb, 1); + /* trim to frame size */ + skb_trim(*skb, phy->priv->ops->rx_frame_size((*skb)->data)); + + return 0; +} + +static irqreturn_t pn533_i2c_irq_thread_fn(int irq, void *data) +{ + struct pn533_i2c_phy *phy = data; + struct i2c_client *client; + struct sk_buff *skb = NULL; + int r; + + if (!phy || irq != phy->i2c_dev->irq) { + WARN_ON_ONCE(1); + return IRQ_NONE; + } + + client = phy->i2c_dev; + dev_dbg(&client->dev, "IRQ\n"); + + if (phy->hard_fault != 0) + return IRQ_HANDLED; + + r = pn533_i2c_read(phy, &skb); + if (r == -EREMOTEIO) { + phy->hard_fault = r; + + pn533_recv_frame(phy->priv, NULL, -EREMOTEIO); + + return IRQ_HANDLED; + } else if ((r == -ENOMEM) || (r == -EBADMSG) || (r == -EBUSY)) { + return IRQ_HANDLED; + } + + pn533_recv_frame(phy->priv, skb, 0); + + return IRQ_HANDLED; +} + +static struct pn533_phy_ops i2c_phy_ops = { + .send_frame = pn533_i2c_send_frame, + .send_ack = pn533_i2c_send_ack, + .abort_cmd = pn533_i2c_abort_cmd, +}; + + +static int pn533_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pn533_i2c_phy *phy; + struct pn533 *priv; + int r = 0; + + dev_dbg(&client->dev, "%s\n", __func__); + dev_dbg(&client->dev, "IRQ: %d\n", client->irq); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + nfc_err(&client->dev, "Need I2C_FUNC_I2C\n"); + return -ENODEV; + } + + phy = devm_kzalloc(&client->dev, sizeof(struct pn533_i2c_phy), + GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->i2c_dev = client; + i2c_set_clientdata(client, phy); + + r = request_threaded_irq(client->irq, NULL, pn533_i2c_irq_thread_fn, + IRQF_TRIGGER_FALLING | + IRQF_SHARED | IRQF_ONESHOT, + PN533_I2C_DRIVER_NAME, phy); + + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); + + priv = pn533_register_device(PN533_DEVICE_PN532, + PN533_NO_TYPE_B_PROTOCOLS, + PN533_PROTO_REQ_ACK_RESP, + phy, &i2c_phy_ops, NULL, + &phy->i2c_dev->dev); + + if (IS_ERR(priv)) { + r = PTR_ERR(priv); + goto err_register; + } + + phy->priv = priv; + + return 0; + +err_register: + free_irq(client->irq, phy); + + return r; +} + +static int pn533_i2c_remove(struct i2c_client *client) +{ + struct pn533_i2c_phy *phy = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "%s\n", __func__); + + pn533_unregister_device(phy->priv); + + return 0; +} + +static const struct of_device_id of_pn533_i2c_match[] = { + { .compatible = "nxp,pn533-i2c", }, + { .compatible = "nxp,pn532-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_pn533_i2c_match); + +static struct i2c_device_id pn533_i2c_id_table[] = { + { PN533_I2C_DRIVER_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pn533_i2c_id_table); + +static struct i2c_driver pn533_i2c_driver = { + .driver = { + .name = PN533_I2C_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_pn533_i2c_match), + }, + .probe = pn533_i2c_probe, + .id_table = pn533_i2c_id_table, + .remove = pn533_i2c_remove, +}; + +module_i2c_driver(pn533_i2c_driver); + +MODULE_AUTHOR("Michael Thalmeier "); +MODULE_DESCRIPTION("PN533 I2C driver ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index 52d83fec5add..ee9e8f1195fa 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -2427,8 +2427,37 @@ static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf) return rc; } +static int pn532_sam_configuration(struct nfc_dev *nfc_dev) +{ + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + struct sk_buff *skb; + struct sk_buff *resp; + + skb = pn533_alloc_skb(dev, 1); + if (!skb) + return -ENOMEM; + + *skb_put(skb, 1) = 0x01; + + resp = pn533_send_cmd_sync(dev, PN533_CMD_SAM_CONFIGURATION, skb); + if (IS_ERR(resp)) + return PTR_ERR(resp); + + dev_kfree_skb(resp); + return 0; +} + static int pn533_dev_up(struct nfc_dev *nfc_dev) { + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + + if (dev->device_type == PN533_DEVICE_PN532) { + int rc = pn532_sam_configuration(nfc_dev); + + if (rc) + return rc; + } + return pn533_rf_field(nfc_dev, 1); } @@ -2461,6 +2490,7 @@ static int pn533_setup(struct pn533 *dev) case PN533_DEVICE_STD: case PN533_DEVICE_PASORI: case PN533_DEVICE_ACR122U: + case PN533_DEVICE_PN532: max_retries.mx_rty_atr = 0x2; max_retries.mx_rty_psl = 0x1; max_retries.mx_rty_passive_act = @@ -2496,6 +2526,7 @@ static int pn533_setup(struct pn533 *dev) switch (dev->device_type) { case PN533_DEVICE_STD: + case PN533_DEVICE_PN532: break; case PN533_DEVICE_PASORI: diff --git a/drivers/nfc/pn533/pn533.h b/drivers/nfc/pn533/pn533.h index 1d9f19eb2a99..ba604f6d93f9 100644 --- a/drivers/nfc/pn533/pn533.h +++ b/drivers/nfc/pn533/pn533.h @@ -21,6 +21,7 @@ #define PN533_DEVICE_STD 0x1 #define PN533_DEVICE_PASORI 0x2 #define PN533_DEVICE_ACR122U 0x3 +#define PN533_DEVICE_PN532 0x4 #define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ @@ -73,6 +74,7 @@ #define PN533_FRAME_CMD(f) (f->data[1]) #define PN533_CMD_GET_FIRMWARE_VERSION 0x02 +#define PN533_CMD_SAM_CONFIGURATION 0x14 #define PN533_CMD_RF_CONFIGURATION 0x32 #define PN533_CMD_IN_DATA_EXCHANGE 0x40 #define PN533_CMD_IN_COMM_THRU 0x42 -- cgit v1.2.3 From 71c08eac2e88b01ecbfba1b1a485a748a4632727 Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Mon, 11 Apr 2016 16:36:02 +0200 Subject: nfc: pn533: Add device tree documentation for i2c phy Add pn533-i2c phy devicetree documentation Signed-off-by: Michael Thalmeier Signed-off-by: Samuel Ortiz --- .../devicetree/bindings/net/nfc/pn533-i2c.txt | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/nfc/pn533-i2c.txt diff --git a/Documentation/devicetree/bindings/net/nfc/pn533-i2c.txt b/Documentation/devicetree/bindings/net/nfc/pn533-i2c.txt new file mode 100644 index 000000000000..1aea822d4530 --- /dev/null +++ b/Documentation/devicetree/bindings/net/nfc/pn533-i2c.txt @@ -0,0 +1,31 @@ +* NXP Semiconductors PN532 NFC Controller + +Required properties: +- compatible: Should be "nxp,pn532-i2c" or "nxp,pn533-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus +- interrupt-parent: phandle for the interrupt gpio controller +- interrupts: GPIO interrupt to which the chip is connected + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBone with PN532 on I2C2): + +&i2c2 { + + status = "okay"; + + pn532: pn532@24 { + + compatible = "nxp,pn532-i2c"; + + reg = <0x24>; + clock-frequency = <400000>; + + interrupt-parent = <&gpio1>; + interrupts = <17 IRQ_TYPE_EDGE_FALLING>; + + }; +}; -- cgit v1.2.3 From dfeb87df484d609aadef810dbb819830f5f9052a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 30 Mar 2016 09:51:04 +0900 Subject: nfc: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Samuel Ortiz --- drivers/nfc/nxp-nci/i2c.c | 1 - drivers/nfc/pn544/i2c.c | 1 - drivers/nfc/st-nci/i2c.c | 1 - drivers/nfc/st21nfca/i2c.c | 1 - 4 files changed, 4 deletions(-) diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c index 11520f472f98..36099e557730 100644 --- a/drivers/nfc/nxp-nci/i2c.c +++ b/drivers/nfc/nxp-nci/i2c.c @@ -418,7 +418,6 @@ MODULE_DEVICE_TABLE(acpi, acpi_id); static struct i2c_driver nxp_nci_i2c_driver = { .driver = { .name = NXP_NCI_I2C_DRIVER_NAME, - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(acpi_id), .of_match_table = of_match_ptr(of_nxp_nci_i2c_match), }, diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index 45d0e667d7ae..f837c39a8017 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -1106,7 +1106,6 @@ MODULE_DEVICE_TABLE(of, of_pn544_i2c_match); static struct i2c_driver pn544_hci_i2c_driver = { .driver = { .name = PN544_HCI_I2C_DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(of_pn544_i2c_match), .acpi_match_table = ACPI_PTR(pn544_hci_i2c_acpi_match), }, diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index 8a56b5c6e4c4..925dbeef74db 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -416,7 +416,6 @@ MODULE_DEVICE_TABLE(of, of_st_nci_i2c_match); static struct i2c_driver st_nci_i2c_driver = { .driver = { - .owner = THIS_MODULE, .name = ST_NCI_I2C_DRIVER_NAME, .of_match_table = of_match_ptr(of_st_nci_i2c_match), .acpi_match_table = ACPI_PTR(st_nci_i2c_acpi_match), diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 1f44a151d206..640b4de05793 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -721,7 +721,6 @@ MODULE_DEVICE_TABLE(of, of_st21nfca_i2c_match); static struct i2c_driver st21nfca_hci_i2c_driver = { .driver = { - .owner = THIS_MODULE, .name = ST21NFCA_HCI_I2C_DRIVER_NAME, .of_match_table = of_match_ptr(of_st21nfca_i2c_match), .acpi_match_table = ACPI_PTR(st21nfca_hci_i2c_acpi_match), -- cgit v1.2.3 From b58afe6d6d3a53af165d5946f12c4b08c95acd58 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:34 +0200 Subject: nfc: st21nfca: Fix static checker warning Fix static checker warning: drivers/nfc/st21nfca/i2c.c:530 st21nfca_hci_i2c_acpi_request_resources() error: 'gpiod_ena' dereferencing possible ERR_PTR() Fix so that if no enable gpio can be retrieved an -ENODEV is returned. Reported-by: Dan Carpenter Fixes: dfa8070d7f64 ("nfc: st21nfca: Add support for acpi probing for i2c device.") Cc: stable@vger.kernel.org Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/i2c.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 640b4de05793..36645dcbe775 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -524,8 +524,10 @@ static int st21nfca_hci_i2c_acpi_request_resources(struct i2c_client *client) /* Get EN GPIO from ACPI */ gpiod_ena = devm_gpiod_get_index(dev, ST21NFCA_GPIO_NAME_EN, 1, GPIOD_OUT_LOW); - if (!IS_ERR(gpiod_ena)) - phy->gpio_ena = desc_to_gpio(gpiod_ena); + if (!IS_ERR(gpiod_ena)) { + nfc_err(dev, "Unable to get ENABLE GPIO\n"); + return -ENODEV; + } phy->gpio_ena = desc_to_gpio(gpiod_ena); -- cgit v1.2.3 From c1fc9136c8b353e853065c2a8a736cdcf6081dcd Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:35 +0200 Subject: nfc: st-nci: i2c: Change ST_NCI_GPIO_NAME_RESET to match DT Since commit 10cf4899f8af ("gpiolib: tighten up ACPI legacy gpio lookups") If _DSD properties are available in an ACPI node, we are not allowed to fallback to _CRS data to retrieve gpio properties. This was causing us to fail if uicc-present and/or ese-present are defined. To be consistent with devicetree change ST_NCI_GPIO_NAME_RESET content to reset so that acpi_find_gpio in drivers/gpio/gpiolib.c will look for reset-gpios. In the mean time the ACPI table needs to be fixed as follow: Device (NFC1) { Name (_ADR, Zero) // _ADR: Address Name (_HID, "SMO2101") // _HID: Hardware ID Name (_CID, "SMO2101") // _CID: Compatible ID Name (_DDN, "SMO NFC") // _DDN: DOS Device Name Name (_UID, One) // _UID: Unique ID Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings { Name (SBUF, ResourceTemplate () { I2cSerialBus (0x0008, ControllerInitiated, 400000, AddressingMode7Bit, "\\_SB.I2C7", 0x00, ResourceConsumer, ,) GpioInt (Edge, ActiveHigh, ExclusiveAndWake, PullNone, 0x0000, "\\_SB.GPO2", 0x00, ResourceConsumer, ,) { // Pin list 0x0001 } GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly, "\\_SB.GPO2", 0x00, ResourceConsumer, ,) { // Pin list 0x0002, } }) Name (_DSD, Package (0x02) { ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301") /* Device Properties for _DSD */, Package (0x03) { Package (0x02) { "uicc-present", 1 }, Package (0x02) { "ese-present", 1 }, Package (0x02) { "reset-gpios", Package(0x04) { ^NFC1, 1, 0, 0} }, } }) Return (SBUF) /* \_SB_.I2C7.NFC1._CRS.SBUF */ } Method (_STA, 0, NotSerialized) // _STA: Status { Return (0x0F) } } Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index 925dbeef74db..6645972377af 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -42,7 +42,7 @@ #define ST_NCI_I2C_DRIVER_NAME "st_nci_i2c" -#define ST_NCI_GPIO_NAME_RESET "clf_reset" +#define ST_NCI_GPIO_NAME_RESET "reset" struct st_nci_i2c_phy { struct i2c_client *i2c_dev; -- cgit v1.2.3 From de72dbc52c4141a6e3f31796499908d00816ad2e Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:36 +0200 Subject: nfc: st-nci: spi: Change ST_NCI_GPIO_NAME_RESET to match DT Since commit 10cf4899f8af ("gpiolib: tighten up ACPI legacy gpio lookups") If _DSD properties are available in an ACPI node, we are not allowed to fallback to _CRS data to retrieve gpio properties. This was causing us to fail if uicc-present and/or ese-present are defined. To be consistent with devicetree change ST_NCI_GPIO_NAME_RESET content to reset so that acpi_find_gpio in drivers/gpio/gpiolib.c will look for reset-gpios. In the mean time the ACPI table needs to be fixed as follow (Tested on Minnowboard Max): Device (NFC1) { Name (_ADR, Zero) // _ADR: Address Name (_HID, "SMO2101") // _HID: Hardware ID Name (_CID, "SMO2101") // _CID: Compatible ID Name (_DDN, "SMO NFC") // _DDN: DOS Device Name Name (_UID, One) // _UID: Unique ID Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings { Name (SBUF, ResourceTemplate () { SpiSerialBus (0, PolarityLow, FourWireMode, 8, ControllerInitiated, 4000000, ClockPolarityLow, ClockPhaseFirst, "\\_SB.SPI1", 0x00, ResourceConsumer, ,) GpioInt (Edge, ActiveHigh, ExclusiveAndWake, PullNone, 0x0000, "\\_SB.GPO2", 0x00, ResourceConsumer, ,) { // Pin list 0x0001 } GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly, "\\_SB.GPO2", 0x00, ResourceConsumer, ,) { // Pin list 0x0002, } }) Name (_DSD, Package (0x02) { ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301") /* Device Properties for _DSD */, Package (0x03) { Package (0x02) { "uicc-present", 1 }, Package (0x02) { "ese-present", 1 }, Package (0x02) { "reset-gpios", Package(0x04) { ^NFC1, 1, 0, 0} }, } }) Return (SBUF) /* \_SB_.SPI1.NFC1._CRS.SBUF */ } Method (_STA, 0, NotSerialized) // _STA: Status { Return (0x0F) } } Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c index 821dfa950fa8..e015015c5dc9 100644 --- a/drivers/nfc/st-nci/spi.c +++ b/drivers/nfc/st-nci/spi.c @@ -43,7 +43,7 @@ #define ST_NCI_SPI_DRIVER_NAME "st_nci_spi" -#define ST_NCI_GPIO_NAME_RESET "clf_reset" +#define ST_NCI_GPIO_NAME_RESET "reset" struct st_nci_spi_phy { struct spi_device *spi_dev; -- cgit v1.2.3 From 2a196975058f94e184464b13b52d86752bccbbd4 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:37 +0200 Subject: nfc: st21nfca: i2c: Change ST21NFCA_GPIO_NAME_RESET to match DT Since commit 10cf4899f8af ("gpiolib: tighten up ACPI legacy gpio lookups") If _DSD properties are available in an ACPI node, we are not allowed to fallback to _CRS data to retrieve gpio properties. This was causing us to fail if uicc-present and/or ese-present are defined. To be consistent with devicetree change ST_NCI_GPIO_NAME_RESET content to reset so that acpi_find_gpio in drivers/gpio/gpiolib.c will look for reset-gpios. In the mean time the ACPI table needs to be fixed as follow: Device (NFC1) { Name (_ADR, Zero) // _ADR: Address Name (_HID, "SMO2100") // _HID: Hardware ID Name (_CID, "SMO2100") // _CID: Compatible ID Name (_DDN, "SMO NFC") // _DDN: DOS Device Name Name (_UID, One) // _UID: Unique ID Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings { Name (SBUF, ResourceTemplate () { I2cSerialBus (0x0008, ControllerInitiated, 400000, AddressingMode7Bit, "\\_SB.I2C7", 0x00, ResourceConsumer, ,) GpioInt (Edge, ActiveHigh, ExclusiveAndWake, PullNone, 0x0000, "\\_SB.GPO2", 0x00, ResourceConsumer, ,) { // Pin list 0x0001 } GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly, "\\_SB.GPO2", 0x00, ResourceConsumer, ,) { // Pin list 0x0002, } }) Name (_DSD, Package (0x02) { ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301") /* Device Properties for _DSD */, Package (0x03) { Package (0x02) { "uicc-present", 1 }, Package (0x02) { "ese-present", 1 }, Package (0x02) { "enable-gpios", Package(0x04) { ^NFC1, 1, 0, 0} }, } }) Return (SBUF) /* \_SB_.I2C7.NFC1._CRS.SBUF */ } Method (_STA, 0, NotSerialized) // _STA: Status { Return (0x0F) } } Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 36645dcbe775..179c0b8edf8d 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -62,7 +62,7 @@ #define ST21NFCA_HCI_I2C_DRIVER_NAME "st21nfca_hci_i2c" -#define ST21NFCA_GPIO_NAME_EN "clf_enable" +#define ST21NFCA_GPIO_NAME_EN "enable" struct st21nfca_i2c_phy { struct i2c_client *i2c_dev; -- cgit v1.2.3 From bd9d523257832ecf999acb0c312f1ee1a22ed4b0 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:38 +0200 Subject: nfc: st21nfca: set is_ese_present and is_uicc_present properly When they're present, set is_ese_present and set is_uicc_present to the value describe in their package description. So far is_ese_present and is_uicc_present was set to true if their property was present. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/i2c.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 179c0b8edf8d..a3153a30be5d 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -510,6 +510,7 @@ static int st21nfca_hci_i2c_acpi_request_resources(struct i2c_client *client) const struct acpi_device_id *id; struct gpio_desc *gpiod_ena; struct device *dev; + u8 tmp; if (!client) return -EINVAL; @@ -533,10 +534,18 @@ static int st21nfca_hci_i2c_acpi_request_resources(struct i2c_client *client) phy->irq_polarity = irq_get_trigger_type(client->irq); - phy->se_status.is_ese_present = - device_property_present(dev, "ese-present"); - phy->se_status.is_uicc_present = - device_property_present(dev, "uicc-present"); + phy->se_status.is_ese_present = false; + phy->se_status.is_uicc_present = false; + + if (device_property_present(dev, "ese-present")) { + device_property_read_u8(dev, "ese-present", &tmp); + phy->se_status.is_ese_present = tmp; + } + + if (device_property_present(dev, "uicc-present")) { + device_property_read_u8(dev, "uicc-present", &tmp); + phy->se_status.is_uicc_present = tmp; + } return 0; } -- cgit v1.2.3 From 27420fec40e22cb3ff04bcef654110eb2ef37620 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:39 +0200 Subject: nfc: st-nci: set is_ese_present and is_uicc_present properly When they're present, set is_ese_present and set is_uicc_present to the value describe in their package description. So far is_ese_present and is_uicc_present was set to true if their property was present. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/i2c.c | 17 +++++++++++++---- drivers/nfc/st-nci/spi.c | 17 +++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index 6645972377af..a6a1977e57c5 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -214,6 +214,7 @@ static int st_nci_i2c_acpi_request_resources(struct i2c_client *client) const struct acpi_device_id *id; struct gpio_desc *gpiod_reset; struct device *dev; + u8 tmp; if (!client) return -EINVAL; @@ -237,10 +238,18 @@ static int st_nci_i2c_acpi_request_resources(struct i2c_client *client) phy->irq_polarity = irq_get_trigger_type(client->irq); - phy->se_status.is_ese_present = - device_property_present(dev, "ese-present"); - phy->se_status.is_uicc_present = - device_property_present(dev, "uicc-present"); + phy->se_status.is_ese_present = false; + phy->se_status.is_uicc_present = false; + + if (device_property_present(dev, "ese-present")) { + device_property_read_u8(dev, "ese-present", &tmp); + phy->se_status.is_ese_present = tmp; + } + + if (device_property_present(dev, "uicc-present")) { + device_property_read_u8(dev, "uicc-present", &tmp); + phy->se_status.is_uicc_present = tmp; + } return 0; } diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c index e015015c5dc9..51a863f0a987 100644 --- a/drivers/nfc/st-nci/spi.c +++ b/drivers/nfc/st-nci/spi.c @@ -229,6 +229,7 @@ static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev) const struct acpi_device_id *id; struct gpio_desc *gpiod_reset; struct device *dev; + u8 tmp; if (!spi_dev) return -EINVAL; @@ -252,10 +253,18 @@ static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev) phy->irq_polarity = irq_get_trigger_type(spi_dev->irq); - phy->se_status.is_ese_present = - device_property_present(dev, "ese-present"); - phy->se_status.is_uicc_present = - device_property_present(dev, "uicc-present"); + phy->se_status.is_ese_present = false; + phy->se_status.is_uicc_present = false; + + if (device_property_present(dev, "ese-present")) { + device_property_read_u8(dev, "ese-present", &tmp); + tmp = phy->se_status.is_ese_present; + } + + if (device_property_present(dev, "uicc-present")) { + device_property_read_u8(dev, "uicc-present", &tmp); + tmp = phy->se_status.is_uicc_present; + } return 0; } -- cgit v1.2.3 From d35cb20b411673820219e08c57392d18668f6217 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:40 +0200 Subject: nfc: st21nfca: Simplify white list building Simplify white list Building Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/core.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/nfc/st21nfca/core.c b/drivers/nfc/st21nfca/core.c index dd8b150fbffa..25ab279606c2 100644 --- a/drivers/nfc/st21nfca/core.c +++ b/drivers/nfc/st21nfca/core.c @@ -262,17 +262,10 @@ static int st21nfca_hci_ready(struct nfc_hci_dev *hdev) int wl_size = 0; int r; - if (info->se_status->is_ese_present && - info->se_status->is_uicc_present) { + if (info->se_status->is_uicc_present) white_list[wl_size++] = NFC_HCI_UICC_HOST_ID; + if (info->se_status->is_ese_present) white_list[wl_size++] = ST21NFCA_ESE_HOST_ID; - } else if (!info->se_status->is_ese_present && - info->se_status->is_uicc_present) { - white_list[wl_size++] = NFC_HCI_UICC_HOST_ID; - } else if (info->se_status->is_ese_present && - !info->se_status->is_uicc_present) { - white_list[wl_size++] = ST21NFCA_ESE_HOST_ID; - } if (wl_size) { r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE, -- cgit v1.2.3 From cde4856e612111ce91258b947051a08703cd1499 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:41 +0200 Subject: nfc: st-nci: Simplify white list building Simplify white list Building Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/se.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c index a53e5df803eb..79efccd13172 100644 --- a/drivers/nfc/st-nci/se.c +++ b/drivers/nfc/st-nci/se.c @@ -629,17 +629,10 @@ int st_nci_discover_se(struct nci_dev *ndev) if (test_bit(ST_NCI_FACTORY_MODE, &info->flags)) return 0; - if (info->se_info.se_status->is_ese_present && - info->se_info.se_status->is_uicc_present) { - white_list[wl_size++] = ST_NCI_UICC_HOST_ID; - white_list[wl_size++] = ST_NCI_ESE_HOST_ID; - } else if (!info->se_info.se_status->is_ese_present && - info->se_info.se_status->is_uicc_present) { + if (info->se_info.se_status->is_uicc_present) white_list[wl_size++] = ST_NCI_UICC_HOST_ID; - } else if (info->se_info.se_status->is_ese_present && - !info->se_info.se_status->is_uicc_present) { + if (info->se_info.se_status->is_ese_present) white_list[wl_size++] = ST_NCI_ESE_HOST_ID; - } if (wl_size) { r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE, -- cgit v1.2.3 From 0209e79d540440962913054fae499ad1892a4f15 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:42 +0200 Subject: nfc: st-nci: A APDU_READER_GATE pipe is unexpected on a UICC An APDU_READER_GATE pipe is not expected on a UICC. Be more explicit so that an other secure element form factor (SD card) does not prompt this message. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/se.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c index 79efccd13172..edb6ee12a372 100644 --- a/drivers/nfc/st-nci/se.c +++ b/drivers/nfc/st-nci/se.c @@ -222,7 +222,7 @@ int st_nci_hci_load_session(struct nci_dev *ndev) */ dm_pipe_info = (struct st_nci_pipe_info *)skb_pipe_info->data; if (dm_pipe_info->dst_gate_id == ST_NCI_APDU_READER_GATE && - dm_pipe_info->src_host_id != ST_NCI_ESE_HOST_ID) { + dm_pipe_info->src_host_id == ST_NCI_UICC_HOST_ID) { pr_err("Unexpected apdu_reader pipe on host %x\n", dm_pipe_info->src_host_id); kfree_skb(skb_pipe_info); -- cgit v1.2.3 From 7cb6ab590d7d203b53284f4f211d4a8a89a125fc Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:43 +0200 Subject: nfc: st21nfca: A APDU_READER_GATE pipe is unexpected on a UICC An APDU_READER_GATE pipe is not expected on a UICC. Be more explicit so that an other secure element form factor (SD card) does not prompt this message. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/st21nfca/core.c b/drivers/nfc/st21nfca/core.c index 25ab279606c2..dacb9166081b 100644 --- a/drivers/nfc/st21nfca/core.c +++ b/drivers/nfc/st21nfca/core.c @@ -176,7 +176,7 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) */ info = (struct st21nfca_pipe_info *) skb_pipe_info->data; if (info->dst_gate_id == ST21NFCA_APDU_READER_GATE && - info->src_host_id != ST21NFCA_ESE_HOST_ID) { + info->src_host_id == NFC_HCI_UICC_HOST_ID) { pr_err("Unexpected apdu_reader pipe on host %x\n", info->src_host_id); kfree_skb(skb_pipe_info); -- cgit v1.2.3 From 070718a499cea9e6d7e6404788490574dfb71388 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:44 +0200 Subject: NFC: st21nfca: Drop two useless checks in ACPI probe path When st21nfca_hci_i2c_acpi_request_resources() gets called we already know that the entries in ->acpi_match_table have matched ACPI ID of the device. In addition I2C client pointer cannot be NULL in any case (otherwise I2C core would not call ->probe() for the driver in the first place). Drop the two useless checks from the driver. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/i2c.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index a3153a30be5d..5a82f553906c 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -507,21 +507,10 @@ static struct nfc_phy_ops i2c_phy_ops = { static int st21nfca_hci_i2c_acpi_request_resources(struct i2c_client *client) { struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client); - const struct acpi_device_id *id; struct gpio_desc *gpiod_ena; - struct device *dev; + struct device *dev = &client->dev; u8 tmp; - if (!client) - return -EINVAL; - - dev = &client->dev; - - /* Match the struct device against a given list of ACPI IDs */ - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return -ENODEV; - /* Get EN GPIO from ACPI */ gpiod_ena = devm_gpiod_get_index(dev, ST21NFCA_GPIO_NAME_EN, 1, GPIOD_OUT_LOW); -- cgit v1.2.3 From 4ac52a0fd066cd33b12d79b09e30fd8bdb52f8d8 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:45 +0200 Subject: NFC: st-nci: i2c: Drop two useless checks in ACPI probe path When st_nci_i2c_acpi_request_resources() gets called we already know that the entries in ->acpi_match_table have matched ACPI ID of the device. In addition I2C client pointer cannot be NULL in any case (otherwise I2C core would not call ->probe() for the driver in the first place). Drop the two useless checks from the driver. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/i2c.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index a6a1977e57c5..9dfae0efa922 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -211,21 +211,10 @@ static struct nfc_phy_ops i2c_phy_ops = { static int st_nci_i2c_acpi_request_resources(struct i2c_client *client) { struct st_nci_i2c_phy *phy = i2c_get_clientdata(client); - const struct acpi_device_id *id; struct gpio_desc *gpiod_reset; - struct device *dev; + struct device *dev = &client->dev; u8 tmp; - if (!client) - return -EINVAL; - - dev = &client->dev; - - /* Match the struct device against a given list of ACPI IDs */ - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return -ENODEV; - /* Get RESET GPIO from ACPI */ gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, 1, GPIOD_OUT_HIGH); -- cgit v1.2.3 From 1f34b20404443717a7ec77b447d86578f0478550 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:46 +0200 Subject: NFC: st-nci: spi: Drop two useless checks in ACPI probe path When st_nci_spi_acpi_request_resources() gets called we already know that the entries in ->acpi_match_table have matched ACPI ID of the device. In addition spi_device pointer cannot be NULL in any case (otherwise SPI core would not call ->probe() for the driver in the first place). Drop the two useless checks from the driver. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/spi.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c index 51a863f0a987..89e341eba3eb 100644 --- a/drivers/nfc/st-nci/spi.c +++ b/drivers/nfc/st-nci/spi.c @@ -226,21 +226,10 @@ static struct nfc_phy_ops spi_phy_ops = { static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev) { struct st_nci_spi_phy *phy = spi_get_drvdata(spi_dev); - const struct acpi_device_id *id; struct gpio_desc *gpiod_reset; - struct device *dev; + struct device *dev = &spi_dev->dev; u8 tmp; - if (!spi_dev) - return -EINVAL; - - dev = &spi_dev->dev; - - /* Match the struct device against a given list of ACPI IDs */ - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return -ENODEV; - /* Get RESET GPIO from ACPI */ gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, 1, GPIOD_OUT_HIGH); -- cgit v1.2.3 From c50e8fef7bb5e4a77609e4120940458e419d463f Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:47 +0200 Subject: nfc: st-nci: Remove redundant ST_NCI_HCI_HOST_ID_ESE from st-nci.h ST_NCI_HCI_HOST_ID_ESE is already having an equivalent in se.c (ST_NCI_ESE_HOST_ID). Remove and replace where relevant. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/se.c | 4 ++-- drivers/nfc/st-nci/st-nci.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c index edb6ee12a372..e7f25f4e3dc3 100644 --- a/drivers/nfc/st-nci/se.c +++ b/drivers/nfc/st-nci/se.c @@ -520,7 +520,7 @@ int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx) * Same for eSE. */ r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_ON); - if (r == ST_NCI_HCI_HOST_ID_ESE) { + if (r == ST_NCI_ESE_HOST_ID) { st_nci_se_get_atr(ndev); r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, ST_NCI_EVT_SE_SOFT_RESET, NULL, 0); @@ -665,7 +665,7 @@ int st_nci_se_io(struct nci_dev *ndev, u32 se_idx, pr_debug("\n"); switch (se_idx) { - case ST_NCI_HCI_HOST_ID_ESE: + case ST_NCI_ESE_HOST_ID: info->se_info.cb = cb; info->se_info.cb_context = cb_context; mod_timer(&info->se_info.bwi_timer, jiffies + diff --git a/drivers/nfc/st-nci/st-nci.h b/drivers/nfc/st-nci/st-nci.h index 8b9f77b0249c..8783f9594d65 100644 --- a/drivers/nfc/st-nci/st-nci.h +++ b/drivers/nfc/st-nci/st-nci.h @@ -32,7 +32,6 @@ * sequence of at most 32 characters. */ #define ST_NCI_ESE_MAX_LENGTH 33 -#define ST_NCI_HCI_HOST_ID_ESE 0xc0 #define ST_NCI_DEVICE_MGNT_GATE 0x01 -- cgit v1.2.3 From 99adc394f2a4a16763bccbaa150b9d598b18c58f Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:48 +0200 Subject: nfc: st21nfca: Remove duplicated ST21NFCA_ESE_HOST_ID from se.c ST21NFCA_ESE_HOST_ID is already defined in st21nfca.h. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/se.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/nfc/st21nfca/se.c b/drivers/nfc/st21nfca/se.c index bd56a16e4007..3a98563d4a12 100644 --- a/drivers/nfc/st21nfca/se.c +++ b/drivers/nfc/st21nfca/se.c @@ -32,8 +32,6 @@ #define ST21NFCA_EVT_CONNECTIVITY 0x10 #define ST21NFCA_EVT_TRANSACTION 0x12 -#define ST21NFCA_ESE_HOST_ID 0xc0 - #define ST21NFCA_SE_TO_HOT_PLUG 1000 /* Connectivity pipe only */ #define ST21NFCA_SE_COUNT_PIPE_UICC 0x01 -- cgit v1.2.3 From 18836029d8c074ac1846167ba702ac528e0a0ad7 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:49 +0200 Subject: nfc: nci: Fix nci_core_conn_create to allowing empty destination NCI_CORE_CONN_CREATE may not have any destination type parameter. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- net/nfc/nci/core.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index fbb7a2b57b44..031ac0f9538c 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -610,9 +610,6 @@ int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type, struct nci_core_conn_create_cmd *cmd; struct core_conn_create_data data; - if (!number_destination_params) - return -EINVAL; - data.length = params_len + sizeof(struct nci_core_conn_create_cmd); cmd = kzalloc(data.length, GFP_KERNEL); if (!cmd) @@ -620,17 +617,20 @@ int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type, cmd->destination_type = destination_type; cmd->number_destination_params = number_destination_params; - memcpy(cmd->params, params, params_len); data.cmd = cmd; - if (params->length > 0) - ndev->cur_id = params->value[DEST_SPEC_PARAMS_ID_INDEX]; - else + if (params) { + memcpy(cmd->params, params, params_len); + if (params->length > 0) + ndev->cur_id = params->value[DEST_SPEC_PARAMS_ID_INDEX]; + else + ndev->cur_id = 0; + } else { ndev->cur_id = 0; + } - r = __nci_request(ndev, nci_core_conn_create_req, - (unsigned long)&data, + r = __nci_request(ndev, nci_core_conn_create_req, (unsigned long)&data, msecs_to_jiffies(NCI_CMD_TIMEOUT)); kfree(cmd); return r; -- cgit v1.2.3 From de5ea8517c2ae40785fe5d0a2d02fc71bef1761b Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:50 +0200 Subject: nfc: nci: Fix nci_core_conn_close nci_core_conn_close was not retrieving a conn_info using the correct connection id. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- net/nfc/nci/core.c | 1 + net/nfc/nci/rsp.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 031ac0f9538c..0884f1444817 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -646,6 +646,7 @@ static void nci_core_conn_close_req(struct nci_dev *ndev, unsigned long opt) int nci_core_conn_close(struct nci_dev *ndev, u8 conn_id) { + ndev->cur_conn_id = conn_id; return __nci_request(ndev, nci_core_conn_close_req, conn_id, msecs_to_jiffies(NCI_CMD_TIMEOUT)); } diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index 9b6eb913d801..69fe163b7350 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -271,7 +271,8 @@ static void nci_core_conn_close_rsp_packet(struct nci_dev *ndev, pr_debug("status 0x%x\n", status); if (status == NCI_STATUS_OK) { - conn_info = nci_get_conn_info_by_conn_id(ndev, ndev->cur_id); + conn_info = nci_get_conn_info_by_conn_id(ndev, + ndev->cur_conn_id); if (conn_info) { list_del(&conn_info->list); devm_kfree(&ndev->nfc_dev->dev, conn_info); -- cgit v1.2.3 From 9b8d1a4cf2aa819d606b4e423a6523fc0d4460a2 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:51 +0200 Subject: nfc: nci: Add an additional parameter to identify a connection id According to NCI specification, destination type and destination specific parameters shall uniquely identify a single destination for the Logical Connection. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/fdp/fdp.c | 3 ++- drivers/nfc/st-nci/se.c | 6 ++++-- include/net/nfc/nci_core.h | 15 ++++++++++++--- net/nfc/nci/core.c | 25 ++++++++++++++++++------- net/nfc/nci/ntf.c | 2 +- net/nfc/nci/rsp.c | 20 +++++++++++++++++--- 6 files changed, 54 insertions(+), 17 deletions(-) diff --git a/drivers/nfc/fdp/fdp.c b/drivers/nfc/fdp/fdp.c index ccb07a1b153d..e44a7a2f4061 100644 --- a/drivers/nfc/fdp/fdp.c +++ b/drivers/nfc/fdp/fdp.c @@ -102,7 +102,8 @@ static int fdp_nci_create_conn(struct nci_dev *ndev) if (r) return r; - return nci_get_conn_info_by_id(ndev, 0); + return nci_get_conn_info_by_dest_type_params(ndev, + FDP_PATCH_CONN_DEST, NULL); } static inline int fdp_nci_get_versions(struct nci_dev *ndev) diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c index e7f25f4e3dc3..420f019cc42f 100644 --- a/drivers/nfc/st-nci/se.c +++ b/drivers/nfc/st-nci/se.c @@ -600,10 +600,12 @@ static int st_nci_hci_network_init(struct nci_dev *ndev) * HCI will be used here only for proprietary commands. */ if (test_bit(ST_NCI_FACTORY_MODE, &info->flags)) - r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id, + r = nci_nfcee_mode_set(ndev, + ndev->hci_dev->conn_info->dest_params->id, NCI_NFCEE_DISABLE); else - r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id, + r = nci_nfcee_mode_set(ndev, + ndev->hci_dev->conn_info->dest_params->id, NCI_NFCEE_ENABLE); free_dest_params: diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index 57ce24fb0047..ebb50d286ef6 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -109,7 +109,13 @@ struct nci_ops { struct nci_conn_info { struct list_head list; - __u8 id; /* can be an RF Discovery ID or an NFCEE ID */ + /* NCI specification 4.4.2 Connection Creation + * The combination of destination type and destination specific + * parameters shall uniquely identify a single destination for the + * Logical Connection + */ + struct dest_spec_params *dest_params; + __u8 dest_type; __u8 conn_id; __u8 max_pkt_payload_len; @@ -260,7 +266,9 @@ struct nci_dev { __u32 manufact_specific_info; /* Save RF Discovery ID or NFCEE ID under conn_create */ - __u8 cur_id; + struct dest_spec_params cur_params; + /* Save destination type under conn_create */ + __u8 cur_dest_type; /* stored during nci_data_exchange */ struct sk_buff *rx_data_reassembly; @@ -378,7 +386,8 @@ void nci_clear_target_list(struct nci_dev *ndev); void nci_req_complete(struct nci_dev *ndev, int result); struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev, int conn_id); -int nci_get_conn_info_by_id(struct nci_dev *ndev, u8 id); +int nci_get_conn_info_by_dest_type_params(struct nci_dev *ndev, u8 dest_type, + struct dest_spec_params *params); /* ----- NCI status code ----- */ int nci_to_errno(__u8 code); diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 0884f1444817..74f2d54df4fc 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -64,18 +64,26 @@ struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev, return NULL; } -int nci_get_conn_info_by_id(struct nci_dev *ndev, u8 id) +int nci_get_conn_info_by_dest_type_params(struct nci_dev *ndev, u8 dest_type, + struct dest_spec_params *params) { struct nci_conn_info *conn_info; list_for_each_entry(conn_info, &ndev->conn_info_list, list) { - if (conn_info->id == id) - return conn_info->conn_id; + if (conn_info->dest_type == dest_type) { + if (!params) + return conn_info->conn_id; + if (conn_info) { + if (params->id == conn_info->dest_params->id && + params->protocol == conn_info->dest_params->protocol) + return conn_info->conn_id; + } + } } return -EINVAL; } -EXPORT_SYMBOL(nci_get_conn_info_by_id); +EXPORT_SYMBOL(nci_get_conn_info_by_dest_type_params); /* ---- NCI requests ---- */ @@ -623,12 +631,15 @@ int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type, if (params) { memcpy(cmd->params, params, params_len); if (params->length > 0) - ndev->cur_id = params->value[DEST_SPEC_PARAMS_ID_INDEX]; + memcpy(&ndev->cur_params, + ¶ms->value[DEST_SPEC_PARAMS_ID_INDEX], + sizeof(struct dest_spec_params)); else - ndev->cur_id = 0; + ndev->cur_params.id = 0; } else { - ndev->cur_id = 0; + ndev->cur_params.id = 0; } + ndev->cur_dest_type = destination_type; r = __nci_request(ndev, nci_core_conn_create_req, (unsigned long)&data, msecs_to_jiffies(NCI_CMD_TIMEOUT)); diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 2ada2b39e355..1e8c1a12aaec 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -734,7 +734,7 @@ static void nci_nfcee_discover_ntf_packet(struct nci_dev *ndev, * “HCI Access”, even if the HCI Network contains multiple NFCEEs. */ ndev->hci_dev->nfcee_id = nfcee_ntf->nfcee_id; - ndev->cur_id = nfcee_ntf->nfcee_id; + ndev->cur_params.id = nfcee_ntf->nfcee_id; nci_req_complete(ndev, status); } diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index 69fe163b7350..e3bbf1937d0e 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -226,7 +226,7 @@ static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) { __u8 status = skb->data[0]; - struct nci_conn_info *conn_info; + struct nci_conn_info *conn_info = NULL; struct nci_core_conn_create_rsp *rsp; pr_debug("status 0x%x\n", status); @@ -241,7 +241,17 @@ static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev, goto exit; } - conn_info->id = ndev->cur_id; + conn_info->dest_params = devm_kzalloc(&ndev->nfc_dev->dev, + sizeof(struct dest_spec_params), + GFP_KERNEL); + if (!conn_info->dest_params) { + status = NCI_STATUS_REJECTED; + goto free_conn_info; + } + + conn_info->dest_type = ndev->cur_dest_type; + conn_info->dest_params->id = ndev->cur_params.id; + conn_info->dest_params->protocol = ndev->cur_params.protocol; conn_info->conn_id = rsp->conn_id; /* Note: data_exchange_cb and data_exchange_cb_context need to @@ -251,7 +261,7 @@ static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev, INIT_LIST_HEAD(&conn_info->list); list_add(&conn_info->list, &ndev->conn_info_list); - if (ndev->cur_id == ndev->hci_dev->nfcee_id) + if (ndev->cur_params.id == ndev->hci_dev->nfcee_id) ndev->hci_dev->conn_info = conn_info; conn_info->conn_id = rsp->conn_id; @@ -259,7 +269,11 @@ static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev, atomic_set(&conn_info->credits_cnt, rsp->credits_cnt); } +free_conn_info: + if (status == NCI_STATUS_REJECTED) + devm_kfree(&ndev->nfc_dev->dev, conn_info); exit: + nci_req_complete(ndev, status); } -- cgit v1.2.3 From 1c53855f6be2e7da270e86cae381745ee6105eab Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:52 +0200 Subject: nfc: nci: Add nci_nfcc_loopback to the nci core For test purpose, provide the generic nci loopback function. Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- include/net/nfc/nci_core.h | 2 ++ net/nfc/nci/core.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index ebb50d286ef6..87499b6b35d6 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -306,6 +306,8 @@ int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type, size_t params_len, struct core_conn_create_dest_spec_params *params); int nci_core_conn_close(struct nci_dev *ndev, u8 conn_id); +int nci_nfcc_loopback(struct nci_dev *ndev, void *data, size_t data_len, + struct sk_buff **resp); struct nci_hci_dev *nci_hci_allocate(struct nci_dev *ndev); int nci_hci_send_event(struct nci_dev *ndev, u8 gate, u8 event, diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 74f2d54df4fc..61fff422424f 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -400,6 +400,83 @@ int nci_core_init(struct nci_dev *ndev) } EXPORT_SYMBOL(nci_core_init); +struct nci_loopback_data { + u8 conn_id; + struct sk_buff *data; +}; + +static void nci_send_data_req(struct nci_dev *ndev, unsigned long opt) +{ + struct nci_loopback_data *data = (struct nci_loopback_data *)opt; + + nci_send_data(ndev, data->conn_id, data->data); +} + +static void nci_nfcc_loopback_cb(void *context, struct sk_buff *skb, int err) +{ + struct nci_dev *ndev = (struct nci_dev *)context; + struct nci_conn_info *conn_info; + + conn_info = nci_get_conn_info_by_conn_id(ndev, ndev->cur_conn_id); + if (!conn_info) { + nci_req_complete(ndev, NCI_STATUS_REJECTED); + return; + } + + conn_info->rx_skb = skb; + + nci_req_complete(ndev, NCI_STATUS_OK); +} + +int nci_nfcc_loopback(struct nci_dev *ndev, void *data, size_t data_len, + struct sk_buff **resp) +{ + int r; + struct nci_loopback_data loopback_data; + struct nci_conn_info *conn_info; + struct sk_buff *skb; + int conn_id = nci_get_conn_info_by_dest_type_params(ndev, + NCI_DESTINATION_NFCC_LOOPBACK, NULL); + + if (conn_id < 0) { + r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCC_LOOPBACK, + 0, 0, NULL); + if (r != NCI_STATUS_OK) + return r; + + conn_id = nci_get_conn_info_by_dest_type_params(ndev, + NCI_DESTINATION_NFCC_LOOPBACK, + NULL); + } + + conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id); + if (!conn_info) + return -EPROTO; + + /* store cb and context to be used on receiving data */ + conn_info->data_exchange_cb = nci_nfcc_loopback_cb; + conn_info->data_exchange_cb_context = ndev; + + skb = nci_skb_alloc(ndev, NCI_DATA_HDR_SIZE + data_len, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, NCI_DATA_HDR_SIZE); + memcpy(skb_put(skb, data_len), data, data_len); + + loopback_data.conn_id = conn_id; + loopback_data.data = skb; + + ndev->cur_conn_id = conn_id; + r = nci_request(ndev, nci_send_data_req, (unsigned long)&loopback_data, + msecs_to_jiffies(NCI_DATA_TIMEOUT)); + if (r == NCI_STATUS_OK && resp) + *resp = conn_info->rx_skb; + + return r; +} +EXPORT_SYMBOL(nci_nfcc_loopback); + static int nci_open_device(struct nci_dev *ndev) { int rc = 0; -- cgit v1.2.3 From 3aacd7fe552b093fc24a8082e16467eb26c2fa32 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Sat, 30 Apr 2016 09:12:53 +0200 Subject: nfc: st-nci: Move loopback usage from HCI to NCI NCI provides possible way to run loopback testing has done over HCI. For us it offers many advantages: - It simplifies the code: No more need for a vendor_cmds structure - Loopback over HCI may not be supported in future st-nci firmware Signed-off-by: Christophe Ricard Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/se.c | 5 ---- drivers/nfc/st-nci/st-nci.h | 13 ++------- drivers/nfc/st-nci/vendor_cmds.c | 62 ++++++++-------------------------------- 3 files changed, 14 insertions(+), 66 deletions(-) diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c index 420f019cc42f..56f2112e0cd8 100644 --- a/drivers/nfc/st-nci/se.c +++ b/drivers/nfc/st-nci/se.c @@ -113,8 +113,6 @@ static struct nci_hci_gate st_nci_gates[] = { {NCI_HCI_IDENTITY_MGMT_GATE, NCI_HCI_INVALID_PIPE, ST_NCI_HOST_CONTROLLER_ID}, - {NCI_HCI_LOOPBACK_GATE, NCI_HCI_INVALID_PIPE, - ST_NCI_HOST_CONTROLLER_ID}, /* Secure element pipes are created by secure element host */ {ST_NCI_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE, @@ -385,9 +383,6 @@ void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe, case ST_NCI_CONNECTIVITY_GATE: st_nci_hci_connectivity_event_received(ndev, host, event, skb); break; - case NCI_HCI_LOOPBACK_GATE: - st_nci_hci_loopback_event_received(ndev, event, skb); - break; } } EXPORT_SYMBOL_GPL(st_nci_hci_event_received); diff --git a/drivers/nfc/st-nci/st-nci.h b/drivers/nfc/st-nci/st-nci.h index 8783f9594d65..afaf138b7e1b 100644 --- a/drivers/nfc/st-nci/st-nci.h +++ b/drivers/nfc/st-nci/st-nci.h @@ -92,8 +92,7 @@ struct st_nci_se_info { * white list). * @HCI_DM_FIELD_GENERATOR: Allow to generate different kind of RF * technology. When using this command to anti-collision is done. - * @HCI_LOOPBACK: Allow to echo a command and test the Dh to CLF - * connectivity. + * @LOOPBACK: Allow to echo a command and test the Dh to CLF connectivity. * @HCI_DM_VDC_MEASUREMENT_VALUE: Allow to measure the field applied on the * CLF antenna. A value between 0 and 0x0f is returned. 0 is maximum. * @HCI_DM_FWUPD_START: Allow to put CLF into firmware update mode. It is a @@ -115,7 +114,7 @@ enum nfc_vendor_cmds { HCI_DM_RESET, HCI_GET_PARAM, HCI_DM_FIELD_GENERATOR, - HCI_LOOPBACK, + LOOPBACK, HCI_DM_FWUPD_START, HCI_DM_FWUPD_END, HCI_DM_VDC_MEASUREMENT_VALUE, @@ -123,17 +122,11 @@ enum nfc_vendor_cmds { MANUFACTURER_SPECIFIC, }; -struct st_nci_vendor_info { - struct completion req_completion; - struct sk_buff *rx_skb; -}; - struct st_nci_info { struct llt_ndlc *ndlc; unsigned long flags; struct st_nci_se_info se_info; - struct st_nci_vendor_info vendor_info; }; void st_nci_remove(struct nci_dev *ndev); @@ -155,8 +148,6 @@ void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe, void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd, struct sk_buff *skb); -void st_nci_hci_loopback_event_received(struct nci_dev *ndev, u8 event, - struct sk_buff *skb); int st_nci_vendor_cmds_init(struct nci_dev *ndev); #endif /* __LOCAL_ST_NCI_H_ */ diff --git a/drivers/nfc/st-nci/vendor_cmds.c b/drivers/nfc/st-nci/vendor_cmds.c index b5debce4ae0b..1a836c77c268 100644 --- a/drivers/nfc/st-nci/vendor_cmds.c +++ b/drivers/nfc/st-nci/vendor_cmds.c @@ -333,62 +333,28 @@ exit: return r; } -void st_nci_hci_loopback_event_received(struct nci_dev *ndev, u8 event, - struct sk_buff *skb) -{ - struct st_nci_info *info = nci_get_drvdata(ndev); - - switch (event) { - case ST_NCI_EVT_POST_DATA: - info->vendor_info.rx_skb = skb; - break; - default: - nfc_err(&ndev->nfc_dev->dev, "Unexpected event on loopback gate\n"); - } - complete(&info->vendor_info.req_completion); -} -EXPORT_SYMBOL(st_nci_hci_loopback_event_received); - -static int st_nci_hci_loopback(struct nfc_dev *dev, void *data, - size_t data_len) +static int st_nci_loopback(struct nfc_dev *dev, void *data, + size_t data_len) { int r; - struct sk_buff *msg; + struct sk_buff *msg, *skb; struct nci_dev *ndev = nfc_get_drvdata(dev); - struct st_nci_info *info = nci_get_drvdata(ndev); if (data_len <= 0) return -EPROTO; - reinit_completion(&info->vendor_info.req_completion); - info->vendor_info.rx_skb = NULL; + r = nci_nfcc_loopback(ndev, data, data_len, &skb); + if (r < 0) + return r; - r = nci_hci_send_event(ndev, NCI_HCI_LOOPBACK_GATE, - ST_NCI_EVT_POST_DATA, data, data_len); - if (r != data_len) { - r = -EPROTO; - goto exit; - } - - wait_for_completion_interruptible(&info->vendor_info.req_completion); - - if (!info->vendor_info.rx_skb || - info->vendor_info.rx_skb->len != data_len) { - r = -EPROTO; - goto exit; - } - - msg = nfc_vendor_cmd_alloc_reply_skb(ndev->nfc_dev, - ST_NCI_VENDOR_OUI, - HCI_LOOPBACK, - info->vendor_info.rx_skb->len); + msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, + LOOPBACK, skb->len); if (!msg) { r = -ENOMEM; goto free_skb; } - if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len, - info->vendor_info.rx_skb->data)) { + if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { kfree_skb(msg); r = -ENOBUFS; goto free_skb; @@ -396,8 +362,7 @@ static int st_nci_hci_loopback(struct nfc_dev *dev, void *data, r = nfc_vendor_cmd_reply(msg); free_skb: - kfree_skb(info->vendor_info.rx_skb); -exit: + kfree_skb(skb); return r; } @@ -485,8 +450,8 @@ static struct nfc_vendor_cmd st_nci_vendor_cmds[] = { }, { .vendor_id = ST_NCI_VENDOR_OUI, - .subcmd = HCI_LOOPBACK, - .doit = st_nci_hci_loopback, + .subcmd = LOOPBACK, + .doit = st_nci_loopback, }, { .vendor_id = ST_NCI_VENDOR_OUI, @@ -507,9 +472,6 @@ static struct nfc_vendor_cmd st_nci_vendor_cmds[] = { int st_nci_vendor_cmds_init(struct nci_dev *ndev) { - struct st_nci_info *info = nci_get_drvdata(ndev); - - init_completion(&info->vendor_info.req_completion); return nfc_set_vendor_cmds(ndev->nfc_dev, st_nci_vendor_cmds, sizeof(st_nci_vendor_cmds)); } -- cgit v1.2.3 From 79f09fa79cefdd9df40c9c590cc8dda544ebff26 Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Thu, 21 Apr 2016 16:43:49 +0200 Subject: NFC: pn533: i2c: free irq on driver remove The requested irq needs to be freed when removing the driver, otherwise a following driver load fails to request the irq. Signed-off-by: Michael Thalmeier Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533/i2c.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nfc/pn533/i2c.c b/drivers/nfc/pn533/i2c.c index 9679aa52c381..1a622e1c0a73 100644 --- a/drivers/nfc/pn533/i2c.c +++ b/drivers/nfc/pn533/i2c.c @@ -236,6 +236,8 @@ static int pn533_i2c_remove(struct i2c_client *client) pn533_unregister_device(phy->priv); + free_irq(client->irq, phy); + return 0; } -- cgit v1.2.3 From b16931b13c67f06ca74cc8d02797de480dea348b Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Thu, 21 Apr 2016 16:43:50 +0200 Subject: NFC: pn533: fix order of initialization Correctly call nfc_set_parent_dev before nfc_register_device. Otherwise the driver will OOPS when being removed. Signed-off-by: Michael Thalmeier Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533/i2c.c | 3 ++- drivers/nfc/pn533/pn533.c | 4 +++- drivers/nfc/pn533/pn533.h | 3 ++- drivers/nfc/pn533/usb.c | 3 +-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/nfc/pn533/i2c.c b/drivers/nfc/pn533/i2c.c index 1a622e1c0a73..0141f19ac5a7 100644 --- a/drivers/nfc/pn533/i2c.c +++ b/drivers/nfc/pn533/i2c.c @@ -211,7 +211,8 @@ static int pn533_i2c_probe(struct i2c_client *client, PN533_NO_TYPE_B_PROTOCOLS, PN533_PROTO_REQ_ACK_RESP, phy, &i2c_phy_ops, NULL, - &phy->i2c_dev->dev); + &phy->i2c_dev->dev, + &client->dev); if (IS_ERR(priv)) { r = PTR_ERR(priv); diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index ee9e8f1195fa..d82eecd8daad 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -2554,7 +2554,8 @@ struct pn533 *pn533_register_device(u32 device_type, void *phy, struct pn533_phy_ops *phy_ops, struct pn533_frame_ops *fops, - struct device *dev) + struct device *dev, + struct device *parent) { struct pn533_fw_version fw_ver; struct pn533 *priv; @@ -2617,6 +2618,7 @@ struct pn533 *pn533_register_device(u32 device_type, goto destroy_wq; } + nfc_set_parent_dev(priv->nfc_dev, parent); nfc_set_drvdata(priv->nfc_dev, priv); rc = nfc_register_device(priv->nfc_dev); diff --git a/drivers/nfc/pn533/pn533.h b/drivers/nfc/pn533/pn533.h index ba604f6d93f9..553c7d171fd1 100644 --- a/drivers/nfc/pn533/pn533.h +++ b/drivers/nfc/pn533/pn533.h @@ -228,7 +228,8 @@ struct pn533 *pn533_register_device(u32 device_type, void *phy, struct pn533_phy_ops *phy_ops, struct pn533_frame_ops *fops, - struct device *dev); + struct device *dev, + struct device *parent); void pn533_unregister_device(struct pn533 *priv); void pn533_recv_frame(struct pn533 *dev, struct sk_buff *skb, int status); diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c index 4f73cbf8ccef..8ca060324b6a 100644 --- a/drivers/nfc/pn533/usb.c +++ b/drivers/nfc/pn533/usb.c @@ -536,7 +536,7 @@ static int pn533_usb_probe(struct usb_interface *interface, priv = pn533_register_device(id->driver_info, protocols, protocol_type, phy, &usb_phy_ops, fops, - &phy->udev->dev); + &phy->udev->dev, &interface->dev); if (IS_ERR(priv)) { rc = PTR_ERR(priv); @@ -544,7 +544,6 @@ static int pn533_usb_probe(struct usb_interface *interface, } phy->priv = priv; - nfc_set_parent_dev(priv->nfc_dev, &interface->dev); usb_set_intfdata(interface, phy); -- cgit v1.2.3 From 30f98489f54e027001cc9b27c59840975871de65 Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Thu, 21 Apr 2016 16:43:51 +0200 Subject: NFC: pn533: i2c: do not call pn533_recv_frame with aborted commands When a command gets aborted the pn533 core does not need any RX frames that may be received until a new frame is sent. Signed-off-by: Michael Thalmeier Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533/i2c.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/nfc/pn533/i2c.c b/drivers/nfc/pn533/i2c.c index 0141f19ac5a7..1dc89248e58e 100644 --- a/drivers/nfc/pn533/i2c.c +++ b/drivers/nfc/pn533/i2c.c @@ -39,6 +39,8 @@ struct pn533_i2c_phy { struct i2c_client *i2c_dev; struct pn533 *priv; + bool aborted; + int hard_fault; /* * < 0 if hardware error occurred (e.g. i2c err) * and prevents normal operation. @@ -71,6 +73,8 @@ static int pn533_i2c_send_frame(struct pn533 *dev, if (phy->priv == NULL) phy->priv = dev; + phy->aborted = false; + print_hex_dump_debug("PN533_i2c TX: ", DUMP_PREFIX_NONE, 16, 1, out->data, out->len, false); @@ -93,13 +97,15 @@ static int pn533_i2c_send_frame(struct pn533 *dev, static void pn533_i2c_abort_cmd(struct pn533 *dev, gfp_t flags) { + struct pn533_i2c_phy *phy = dev->phy; + + phy->aborted = true; + /* An ack will cancel the last issued command */ pn533_i2c_send_ack(dev, flags); /* schedule cmd_complete_work to finish current command execution */ - if (dev->cmd != NULL) - dev->cmd->status = -ENOENT; - queue_work(dev->wq, &dev->cmd_complete_work); + pn533_recv_frame(phy->priv, NULL, -ENOENT); } static int pn533_i2c_read(struct pn533_i2c_phy *phy, struct sk_buff **skb) @@ -164,7 +170,8 @@ static irqreturn_t pn533_i2c_irq_thread_fn(int irq, void *data) return IRQ_HANDLED; } - pn533_recv_frame(phy->priv, skb, 0); + if (!phy->aborted) + pn533_recv_frame(phy->priv, skb, 0); return IRQ_HANDLED; } -- cgit v1.2.3 From c952f915ce8567120ffdf12998ad0c945fbc93ac Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Thu, 21 Apr 2016 16:43:52 +0200 Subject: NFC: pn533: reset poll modulation list before calling targets_found We need to reset the poll modulation list before calling nfc_targets_found because otherwise userspace could run before the modulation list is cleared and then get a "Cannot activate target while polling" error upon calling activate_target. Signed-off-by: Michael Thalmeier Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533/pn533.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index d82eecd8daad..745181ea693b 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -865,6 +865,7 @@ static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data, return 0; } +static void pn533_poll_reset_mod_list(struct pn533 *dev); static int pn533_target_found(struct pn533 *dev, u8 tg, u8 *tgdata, int tgdata_len) { @@ -914,6 +915,7 @@ static int pn533_target_found(struct pn533 *dev, u8 tg, u8 *tgdata, dev->tgt_available_prots = nfc_tgt.supported_protocols; + pn533_poll_reset_mod_list(dev); nfc_targets_found(dev->nfc_dev, &nfc_tgt, 1); return 0; @@ -980,10 +982,8 @@ static int pn533_start_poll_complete(struct pn533 *dev, struct sk_buff *resp) rc = pn533_target_found(dev, tg, tgdata, tgdata_len); /* We must stop the poll after a valid target found */ - if (rc == 0) { - pn533_poll_reset_mod_list(dev); + if (rc == 0) return 0; - } } return -EAGAIN; -- cgit v1.2.3 From b31d5103c33280738188c51e226224dff4401c7b Mon Sep 17 00:00:00 2001 From: Michael Thalmeier Date: Thu, 21 Apr 2016 16:43:53 +0200 Subject: NFC: pn533: handle interrupted commands in pn533_recv_frame When pn533_recv_frame is called from within abort_command context the current dev->cmd is not guaranteed to be set. Additionally on receiving an error status we can omit frame checking and simply schedule the workqueue. Signed-off-by: Michael Thalmeier Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533/pn533.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index 745181ea693b..d9c55830b2b2 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -2016,8 +2016,16 @@ _error: */ void pn533_recv_frame(struct pn533 *dev, struct sk_buff *skb, int status) { + if (!dev->cmd) + goto sched_wq; + dev->cmd->status = status; + if (status != 0) { + dev_dbg(dev->dev, "%s: Error received: %d\n", __func__, status); + goto sched_wq; + } + if (skb == NULL) { pr_err("NULL Frame -> link is dead\n"); goto sched_wq; -- cgit v1.2.3