NFC changes for 3.5
Subsystems (3)
cover NFC changes for 3.5
Hi John,
This is my current NFC patchset for the next merge window. This is what we mainly have:
* An HCI and SHDLC implementation from Eric.
* A bunch of LLCP fixes.
* Some pn533 changes (workqueue conversion and Rx chaining support).
* A new netlink API for exposing lost targets events.
Please note that the first patch from this serie is a 3.4 fix.
You can also fetch those patches from here:
git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-3.0.git nfc-next
Eric Lapuyade (7):
NFC: Export target lost function
NFC: HCI support
NFC: SHDLC implementation
NFC: Add HCI documentation
NFC: Fix next target_idx type and rename for clarity
NFC: Changed target activated state logic
NFC: Add Core support to generate tag lost event
Samuel Ortiz (11):
NFC: Fix the LLCP Tx fragmentation loop
NFC: Add a target lost netlink event
NFC: The core part should generate the target index
NFC: Dump LLCP frames
NFC: No need to apply twice the modulo op to LLCP's recv_n
NFC: Fix LLCP TLV building routine
NFC: Call llcp_add_header properly when sending LLCP DM or DISC
NFC: Convert pn533 from tasklet to workqueues
NFC: pn533 Rx chaining support
NFC: Add MIUX to the local LLCP general bytes
NFC: Fix LLCP link timeout typo
Documentation/nfc/nfc-hci.txt | 155 +++++++ drivers/nfc/pn533.c | 228 ++++++++--- include/linux/nfc.h | 1 + include/net/nfc/hci.h | 198 +++++++++ include/net/nfc/nfc.h | 12 +- include/net/nfc/shdlc.h | 104 +++++ net/nfc/Kconfig | 1 + net/nfc/Makefile | 1 + net/nfc/core.c | 140 ++++++- net/nfc/hci/Kconfig | 16 + net/nfc/hci/Makefile | 8 + net/nfc/hci/command.c | 354 +++++++++++++++ net/nfc/hci/core.c | 830 ++++++++++++++++++++++++++++++++++++ net/nfc/hci/hci.h | 139 ++++++ net/nfc/hci/hcp.c | 156 +++++++ net/nfc/hci/shdlc.c | 945 +++++++++++++++++++++++++++++++++++++++++ net/nfc/llcp/commands.c | 12 +- net/nfc/llcp/llcp.c | 21 +- net/nfc/nci/core.c | 2 +- net/nfc/nci/ntf.c | 11 +- net/nfc/netlink.c | 30 ++ net/nfc/nfc.h | 1 + net/nfc/rawsock.c | 6 + 23 files changed, 3299 insertions(+), 72 deletions(-) create mode 100644 Documentation/nfc/nfc-hci.txt create mode 100644 include/net/nfc/hci.h create mode 100644 include/net/nfc/shdlc.h create mode 100644 net/nfc/hci/Kconfig create mode 100644 net/nfc/hci/Makefile create mode 100644 net/nfc/hci/command.c create mode 100644 net/nfc/hci/core.c create mode 100644 net/nfc/hci/hci.h create mode 100644 net/nfc/hci/hcp.c create mode 100644 net/nfc/hci/shdlc.c
Signature · 1 line
1.7.9.1
PATCH 1/18 NFC: Fix the LLCP Tx fragmentation loop
--- net/nfc/llcp/commands.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
net/nfc/llcp/commands.c +2 -2
@@ -474,7 +474,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,while (remaining_len >0 ) { - frag_len =min_t (u16, local->remote_miu, remaining_len); + frag_len =min_t (size_t, local->remote_miu, remaining_len);pr_debug ("Fragment %zd bytes remaining %zd" , frag_len, remaining_len);
@@ -497,7 +497,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,release_sock (sk); remaining_len -= frag_len; - msg_ptr += len; + msg_ptr += frag_len; }kfree (msg_data);
Signature · 1 line
1.7.9.1
PATCH 2/18 NFC: Add a target lost netlink event
In reply to Samuel OrtizSome chips are capable of detecting when a tag is out of the field, so they could send a netlink event about it to userspace.
--- include/linux/nfc.h | 1 + net/nfc/netlink.c | 30 ++++++++++++++++++++++++++++++ net/nfc/nfc.h | 1 + 3 files changed, 32 insertions(+), 0 deletions(-)
include/linux/nfc.h +1 -0
@@ -70,6 +70,7 @@ enum nfc_commands {NFC_EVENT_TARGETS_FOUND ,NFC_EVENT_DEVICE_ADDED ,NFC_EVENT_DEVICE_REMOVED , +NFC_EVENT_TARGET_LOST ,/* private: internal use only */ __NFC_CMD_AFTER_LAST };
net/nfc/netlink.c +30 -0
@@ -183,6 +183,36 @@ free_msg:return -EMSGSIZE ; } +int nfc_genl_target_lost (struct nfc_dev *dev,u32 target_idx) +{ +struct sk_buff *msg; +void *hdr; + + msg =nlmsg_new (NLMSG_GOODSIZE ,GFP_KERNEL ); +if (!msg) +return -ENOMEM ; + + hdr =genlmsg_put (msg,0 ,0 , &nfc_genl_family,0 , +NFC_EVENT_TARGET_LOST ); +if (!hdr) + goto free_msg; + +NLA_PUT_STRING (msg,NFC_ATTR_DEVICE_NAME ,nfc_device_name (dev)); +NLA_PUT_U32 (msg,NFC_ATTR_TARGET_INDEX , target_idx); + +genlmsg_end (msg, hdr); + +genlmsg_multicast (msg,0 , nfc_genl_event_mcgrp.id,GFP_KERNEL ); + +return 0 ; + +nla_put_failure: +genlmsg_cancel (msg, hdr); +free_msg: +nlmsg_free (msg); +return -EMSGSIZE ; +} +int nfc_genl_device_added (struct nfc_dev *dev) {struct sk_buff *msg;
net/nfc/nfc.h +1 -0
@@ -119,6 +119,7 @@ void nfc_genl_data_init(struct nfc_genl_data *genl_data);void nfc_genl_data_exit (struct nfc_genl_data *genl_data);int nfc_genl_targets_found (struct nfc_dev *dev); +int nfc_genl_target_lost (struct nfc_dev *dev,u32 target_idx);int nfc_genl_device_added (struct nfc_dev *dev);int nfc_genl_device_removed (struct nfc_dev *dev);
Signature · 1 line
1.7.9.1
PATCH 3/18 NFC: Export target lost function
In reply to Samuel OrtizFrom: Eric Lapuyade <[email protected]>
NFC drivers will call this routine when they detect that a tag leaves the RF field. This will eventually lead to the corresponding netlink event to be sent.
--- include/net/nfc/nfc.h | 1 + net/nfc/core.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 0 deletions(-)
include/net/nfc/nfc.h +1 -0
@@ -181,6 +181,7 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev,int nfc_targets_found (struct nfc_dev *dev,struct nfc_target *targets,int ntargets); +int nfc_target_lost (struct nfc_dev *dev,u32 target_idx);int nfc_dep_link_is_up (struct nfc_dev *dev,u32 target_idx,u8 comm_mode,u8 rf_mode);
net/nfc/core.c +39 -0
@@ -455,6 +455,45 @@ int nfc_targets_found(struct nfc_dev *dev, }EXPORT_SYMBOL (nfc_targets_found); +int nfc_target_lost (struct nfc_dev *dev,u32 target_idx) +{ +struct nfc_target *tg; +int i; + +pr_debug ("dev_name %s n_target %d\n" ,dev_name (&dev->dev), target_idx); + +spin_lock_bh (&dev->targets_lock); + +for (i =0 ; i < dev->n_targets; i++) { + tg = &dev->targets[i]; +if (tg->idx == target_idx) +break ; + } + +if (i == dev->n_targets) { +spin_unlock_bh (&dev->targets_lock); +return -EINVAL ; + } + + dev->targets_generation++; + dev->n_targets--; + +if (dev->n_targets) { +memcpy (&dev->targets[i], &dev->targets[i +1 ], + (dev->n_targets - i) *sizeof (struct nfc_target )); + }else { +kfree (dev->targets); + dev->targets =NULL ; + } + +spin_unlock_bh (&dev->targets_lock); + +nfc_genl_target_lost (dev, target_idx); + +return 0 ; +} +EXPORT_SYMBOL (nfc_target_lost); +static void nfc_release (struct device *d) {struct nfc_dev *dev =to_nfc_dev (d);
Signature · 1 line
1.7.9.1
PATCH 4/18 NFC: HCI support
In reply to Samuel OrtizFrom: Eric Lapuyade <[email protected]>
This is an implementation of ETSI TS 102 622 specification. Many NFC chipsets use HCI as the host <-> target protocol on top of a serial link like i2c.
--- include/net/nfc/hci.h | 198 ++++++++++++ include/net/nfc/nfc.h | 1 + net/nfc/Kconfig | 1 + net/nfc/Makefile | 1 + net/nfc/hci/Kconfig | 8 + net/nfc/hci/Makefile | 7 + net/nfc/hci/command.c | 354 +++++++++++++++++++++ net/nfc/hci/core.c | 830 +++++++++++++++++++++++++++++++++++++++++++++++++ net/nfc/hci/hci.h | 139 ++++++++ net/nfc/hci/hcp.c | 156 +++++++++ 10 files changed, 1695 insertions(+), 0 deletions(-) create mode 100644 include/net/nfc/hci.h create mode 100644 net/nfc/hci/Kconfig create mode 100644 net/nfc/hci/Makefile create mode 100644 net/nfc/hci/command.c create mode 100644 net/nfc/hci/core.c create mode 100644 net/nfc/hci/hci.h create mode 100644 net/nfc/hci/hcp.c
include/net/nfc/hci.h new file +198 -0
@@ -0,0 +1,198 @@ +/* +* Copyright (C) 2011 Intel Corporation. All rights reserved. +* +* 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, write to the +* Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __NET_HCI_H +#define __NET_HCI_H + +#include <linux/skbuff.h> + +#include <net/nfc/nfc.h> + +struct nfc_hci_dev ; + +struct nfc_hci_ops { +int (*open) (struct nfc_hci_dev *hdev); +void (*close) (struct nfc_hci_dev *hdev); +int (*hci_ready) (struct nfc_hci_dev *hdev); +int (*xmit) (struct nfc_hci_dev *hdev,struct sk_buff *skb); +int (*start_poll) (struct nfc_hci_dev *hdev,u32 protocols); +int (*target_from_gate) (struct nfc_hci_dev *hdev,u8 gate, +struct nfc_target *target); +int (*complete_target_discovered) (struct nfc_hci_dev *hdev,u8 gate, +struct nfc_target *target); +int (*data_exchange) (struct nfc_hci_dev *hdev, +struct nfc_target *target, +struct sk_buff *skb,struct sk_buff **res_skb); +}; + +#define NFC_HCI_MAX_CUSTOM_GATES 15 +struct nfc_hci_init_data { +u8 gate_count; +u8 gates[NFC_HCI_MAX_CUSTOM_GATES ]; +char session_id[9 ]; +}; + +typedef int (*xmit ) (struct sk_buff *skb,void *cb_data); + +#define NFC_HCI_MAX_GATES 256 + +struct nfc_hci_dev { +struct nfc_dev *ndev; + +u32 max_data_link_payload; + +struct mutex msg_tx_mutex; + +struct list_head msg_tx_queue; + +struct workqueue_struct *msg_tx_wq; +struct work_struct msg_tx_work; + +struct timer_list cmd_timer; +struct hci_msg *cmd_pending_msg; + +struct sk_buff_head rx_hcp_frags; + +struct workqueue_struct *msg_rx_wq; +struct work_struct msg_rx_work; + +struct sk_buff_head msg_rx_queue; + +struct nfc_hci_ops *ops; + +struct nfc_hci_init_data init_data; + +void *clientdata; + +u8 gate2pipe[NFC_HCI_MAX_GATES ]; + +bool poll_started; +struct nfc_target *targets; +int target_count; + +u8 sw_romlib; +u8 sw_patch; +u8 sw_flashlib_major; +u8 sw_flashlib_minor; + +u8 hw_derivative; +u8 hw_version; +u8 hw_mpw; +u8 hw_software; +u8 hw_bsid; +}; + +/* hci device allocation */ +struct nfc_hci_dev *nfc_hci_allocate_device (struct nfc_hci_ops *ops, +struct nfc_hci_init_data *init_data, +u32 protocols, +int tx_headroom, +int tx_tailroom, +int max_link_payload); +void nfc_hci_free_device (struct nfc_hci_dev *hdev); + +int nfc_hci_register_device (struct nfc_hci_dev *hdev); +void nfc_hci_unregister_device (struct nfc_hci_dev *hdev); + +void nfc_hci_set_clientdata (struct nfc_hci_dev *hdev,void *clientdata); +void *nfc_hci_get_clientdata (struct nfc_hci_dev *hdev); + +/* Host IDs */ +#define NFC_HCI_HOST_CONTROLLER_ID 0x00 +#define NFC_HCI_TERMINAL_HOST_ID 0x01 +#define NFC_HCI_UICC_HOST_ID 0x02 + +/* Host Controller Gates and registry indexes */ +#define NFC_HCI_ADMIN_GATE 0x00 +#define NFC_HCI_ADMIN_SESSION_IDENTITY 0x01 +#define NFC_HCI_ADMIN_MAX_PIPE 0x02 +#define NFC_HCI_ADMIN_WHITELIST 0x03 +#define NFC_HCI_ADMIN_HOST_LIST 0x04 + +#define NFC_HCI_LOOPBACK_GATE 0x04 + +#define NFC_HCI_ID_MGMT_GATE 0x05 +#define NFC_HCI_ID_MGMT_VERSION_SW 0x01 +#define NFC_HCI_ID_MGMT_VERSION_HW 0x03 +#define NFC_HCI_ID_MGMT_VENDOR_NAME 0x04 +#define NFC_HCI_ID_MGMT_MODEL_ID 0x05 +#define NFC_HCI_ID_MGMT_HCI_VERSION 0x02 +#define NFC_HCI_ID_MGMT_GATES_LIST 0x06 + +#define NFC_HCI_LINK_MGMT_GATE 0x06 +#define NFC_HCI_LINK_MGMT_REC_ERROR 0x01 + +#define NFC_HCI_RF_READER_B_GATE 0x11 +#define NFC_HCI_RF_READER_B_PUPI 0x03 +#define NFC_HCI_RF_READER_B_APPLICATION_DATA 0x04 +#define NFC_HCI_RF_READER_B_AFI 0x02 +#define NFC_HCI_RF_READER_B_HIGHER_LAYER_RESPONSE 0x01 +#define NFC_HCI_RF_READER_B_HIGHER_LAYER_DATA 0x05 + +#define NFC_HCI_RF_READER_A_GATE 0x13 +#define NFC_HCI_RF_READER_A_UID 0x02 +#define NFC_HCI_RF_READER_A_ATQA 0x04 +#define NFC_HCI_RF_READER_A_APPLICATION_DATA 0x05 +#define NFC_HCI_RF_READER_A_SAK 0x03 +#define NFC_HCI_RF_READER_A_FWI_SFGT 0x06 +#define NFC_HCI_RF_READER_A_DATARATE_MAX 0x01 + +#define NFC_HCI_TYPE_A_SEL_PROT (x) (((x) & 0x60) >> 5) +#define NFC_HCI_TYPE_A_SEL_PROT_MIFARE 0 +#define NFC_HCI_TYPE_A_SEL_PROT_ISO14443 1 +#define NFC_HCI_TYPE_A_SEL_PROT_DEP 2 +#define NFC_HCI_TYPE_A_SEL_PROT_ISO14443_DEP 3 + +/* Generic events */ +#define NFC_HCI_EVT_HCI_END_OF_OPERATION 0x01 +#define NFC_HCI_EVT_POST_DATA 0x02 +#define NFC_HCI_EVT_HOT_PLUG 0x03 + +/* Reader RF gates events */ +#define NFC_HCI_EVT_READER_REQUESTED 0x10 +#define NFC_HCI_EVT_END_OPERATION 0x11 + +/* Reader Application gate events */ +#define NFC_HCI_EVT_TARGET_DISCOVERED 0x10 + +/* receiving messages from lower layer */ +void nfc_hci_resp_received (struct nfc_hci_dev *hdev,u8 result, +struct sk_buff *skb); +void nfc_hci_cmd_received (struct nfc_hci_dev *hdev,u8 pipe,u8 cmd, +struct sk_buff *skb); +void nfc_hci_event_received (struct nfc_hci_dev *hdev,u8 pipe,u8 event, +struct sk_buff *skb); +void nfc_hci_recv_frame (struct nfc_hci_dev *hdev,struct sk_buff *skb); + +/* connecting to gates and sending hci instructions */ +int nfc_hci_connect_gate (struct nfc_hci_dev *hdev,u8 dest_host,u8 dest_gate); +int nfc_hci_disconnect_gate (struct nfc_hci_dev *hdev,u8 gate); +int nfc_hci_disconnect_all_gates (struct nfc_hci_dev *hdev); +int nfc_hci_get_param (struct nfc_hci_dev *hdev,u8 gate,u8 idx, +struct sk_buff **skb); +int nfc_hci_set_param (struct nfc_hci_dev *hdev,u8 gate,u8 idx, +const u8 *param,size_t param_len); +int nfc_hci_send_cmd (struct nfc_hci_dev *hdev,u8 gate,u8 cmd, +const u8 *param,size_t param_len,struct sk_buff **skb); +int nfc_hci_send_response (struct nfc_hci_dev *hdev,u8 gate,u8 response, +const u8 *param,size_t param_len); +int nfc_hci_send_event (struct nfc_hci_dev *hdev,u8 gate,u8 event, +const u8 *param,size_t param_len); + +#endif /* __NET_HCI_H */
include/net/nfc/nfc.h +1 -0
@@ -78,6 +78,7 @@ struct nfc_target {u8 sensb_res[NFC_SENSB_RES_MAXSIZE ];u8 sensf_res_len;u8 sensf_res[NFC_SENSF_RES_MAXSIZE ]; +u8 hci_reader_gate; };struct nfc_genl_data {
net/nfc/Kconfig +1 -0
@@ -14,6 +14,7 @@ menuconfig NFC be called nfc. source "net/nfc/nci/Kconfig" +source "net/nfc/hci/Kconfig" source "net/nfc/llcp/Kconfig" source "drivers/nfc/Kconfig"
net/nfc/Makefile +1 -0
@@ -4,6 +4,7 @@ obj-$(CONFIG_NFC) += nfc.o obj-$(CONFIG_NFC_NCI) += nci/ +obj-$(CONFIG_NFC_HCI) += hci/ nfc-objs := core.o netlink.o af_nfc.o rawsock.o nfc-$(CONFIG_NFC_LLCP) += llcp/llcp.o llcp/commands.o llcp/sock.o
net/nfc/hci/Kconfig new file +8 -0
@@ -0,0 +1,8 @@ +config NFC_HCI + depends on NFC + tristate "NFC HCI implementation" + default n + help + Say Y here if you want to build support for a kernel NFC HCI + implementation. This is mostly needed for devices that only process + HCI frames, like for example the NXP pn544.
net/nfc/hci/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +# +# Makefile for the Linux NFC HCI layer. +# + +obj-$(CONFIG_NFC_HCI) += hci.o + +hci-y := core.o hcp.o command.o
net/nfc/hci/command.c new file +354 -0
354 lines not on this page · raw message
net/nfc/hci/core.c new file +830 -0
830 lines not on this page · raw message
net/nfc/hci/hci.h new file +139 -0
139 lines not on this page · raw message
net/nfc/hci/hcp.c new file +156 -0
156 lines not on this page · raw message
Signature · 1 line
1.7.9.1
PATCH 5/18 NFC: SHDLC implementation
In reply to Samuel OrtizFrom: Eric Lapuyade <[email protected]>
Most NFC HCI chipsets actually use a simplified HDLC link layer to carry HCI payloads.
This implementation registers itself as an HCI device on behalf of the NFC driver.
--- include/net/nfc/shdlc.h | 104 ++++++ net/nfc/hci/Kconfig | 8 + net/nfc/hci/Makefile | 1 + net/nfc/hci/shdlc.c | 945 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1058 insertions(+), 0 deletions(-) create mode 100644 include/net/nfc/shdlc.h create mode 100644 net/nfc/hci/shdlc.c
include/net/nfc/shdlc.h new file +104 -0
@@ -0,0 +1,104 @@ +/* +* Copyright (C) 2012 Intel Corporation. All rights reserved. +* +* 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, write to the +* Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef __NFC_SHDLC_H +#define __NFC_SHDLC_H + +struct nfc_shdlc ; + +struct nfc_shdlc_ops { +int (*open) (struct nfc_shdlc *shdlc); +void (*close) (struct nfc_shdlc *shdlc); +int (*hci_ready) (struct nfc_shdlc *shdlc); +int (*xmit) (struct nfc_shdlc *shdlc,struct sk_buff *skb); +int (*start_poll) (struct nfc_shdlc *shdlc,u32 protocols); +int (*target_from_gate) (struct nfc_shdlc *shdlc,u8 gate, +struct nfc_target *target); +int (*complete_target_discovered) (struct nfc_shdlc *shdlc,u8 gate, +struct nfc_target *target); +int (*data_exchange) (struct nfc_shdlc *shdlc, +struct nfc_target *target, +struct sk_buff *skb,struct sk_buff **res_skb); +}; + +enum shdlc_state { +SHDLC_DISCONNECTED =0 , +SHDLC_CONNECTING =1 , +SHDLC_NEGOCIATING =2 , +SHDLC_CONNECTED =3 +}; + +struct nfc_shdlc { +struct mutex state_mutex; +enum shdlc_state state; +int hard_fault; + +struct nfc_hci_dev *hdev; + +wait_queue_head_t *connect_wq; +int connect_tries; +int connect_result; +struct timer_list connect_timer;/* aka T3 in spec 10.6.1 */ + +u8 w;/* window size */ +bool srej_support; + +struct timer_list t1_timer;/* send ack timeout */ +bool t1_active; + +struct timer_list t2_timer;/* guard/retransmit timeout */ +bool t2_active; + +int ns;/* next seq num for send */ +int nr;/* next expected seq num for receive */ +int dnr;/* oldest sent unacked seq num */ + +struct sk_buff_head rcv_q; + +struct sk_buff_head send_q; +bool rnr;/* other side is not ready to receive */ + +struct sk_buff_head ack_pending_q; + +struct workqueue_struct *sm_wq; +struct work_struct sm_work; + +struct nfc_shdlc_ops *ops; + +int client_headroom; +int client_tailroom; + +void *clientdata; +}; + +void nfc_shdlc_recv_frame (struct nfc_shdlc *shdlc,struct sk_buff *skb); + +struct nfc_shdlc *nfc_shdlc_allocate (struct nfc_shdlc_ops *ops, +struct nfc_hci_init_data *init_data, +u32 protocols, +int tx_headroom,int tx_tailroom, +int max_link_payload,const char *devname); + +void nfc_shdlc_free (struct nfc_shdlc *shdlc); + +void nfc_shdlc_set_clientdata (struct nfc_shdlc *shdlc,void *clientdata); +void *nfc_shdlc_get_clientdata (struct nfc_shdlc *shdlc); +struct nfc_hci_dev *nfc_shdlc_get_hci_dev (struct nfc_shdlc *shdlc); + +#endif /* __NFC_SHDLC_H */
net/nfc/hci/Kconfig +8 -0
@@ -6,3 +6,11 @@ config NFC_HCI Say Y here if you want to build support for a kernel NFC HCI implementation. This is mostly needed for devices that only process HCI frames, like for example the NXP pn544. + +config NFC_SHDLC + depends on NFC_HCI + bool "SHDLC link layer for HCI based NFC drivers" + default n + ---help--- + Say yes if you use an NFC HCI driver that requires SHDLC link layer. + If unsure, say N here.
net/nfc/hci/Makefile +1 -0
@@ -5,3 +5,4 @@ obj-$(CONFIG_NFC_HCI) += hci.o hci-y := core.o hcp.o command.o +hci-$(CONFIG_NFC_SHDLC) += shdlc.o
net/nfc/hci/shdlc.c new file +945 -0
945 lines not on this page · raw message
Signature · 1 line
1.7.9.1
PATCH 6/18 NFC: Add HCI documentation
In reply to Samuel OrtizFrom: Eric Lapuyade <[email protected]>
--- Documentation/nfc/nfc-hci.txt | 155 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 155 insertions(+), 0 deletions(-) create mode 100644 Documentation/nfc/nfc-hci.txt
Documentation/nfc/nfc-hci.txt new file +155 -0
@@ -0,0 +1,155 @@ +HCI backend for NFC Core + +Author: Eric Lapuyade, Samuel Ortiz +Contact: [email protected], [email protected] + +General +------- + +The HCI layer implements much of the ETSI TS 102 622 V10.2.0 specification. It +enables easy writing of HCI-based NFC drivers. The HCI layer runs as an NFC Core +backend, implementing an abstract nfc device and translating NFC Core API +to HCI commands and events. + +HCI +--- + +HCI registers as an nfc device with NFC Core. Requests coming from userspace are +routed through netlink sockets to NFC Core and then to HCI. From this point, +they are translated in a sequence of HCI commands sent to the HCI layer in the +host controller (the chip). The sending context blocks while waiting for the +response to arrive. +HCI events can also be received from the host controller. They will be handled +and a translation will be forwarded to NFC Core as needed. +HCI uses 2 execution contexts: +- one if for executing commands : nfc_hci_msg_tx_work(). Only one command +can be executing at any given moment. +- one if for dispatching received events and responses : nfc_hci_msg_rx_work() + +HCI Session initialization: +--------------------------- + +The Session initialization is an HCI standard which must unfortunately +support proprietary gates. This is the reason why the driver will pass a list +of proprietary gates that must be part of the session. HCI will ensure all +those gates have pipes connected when the hci device is set up. + +HCI Gates and Pipes +------------------- + +A gate defines the 'port' where some service can be found. In order to access +a service, one must create a pipe to that gate and open it. In this +implementation, pipes are totally hidden. The public API only knows gates. +This is consistent with the driver need to send commands to proprietary gates +without knowing the pipe connected to it. + +Driver interface +---------------- + +A driver would normally register itself with HCI and provide the following +entry points: + +struct nfc_hci_ops { + int (*open)(struct nfc_hci_dev *hdev); + void (*close)(struct nfc_hci_dev *hdev); + int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb); + int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols); + int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate, + struct nfc_target *target); +}; + +open() and close() shall turn the hardware on and off. xmit() shall simply +write a frame to the chip. start_poll() is an optional entrypoint that shall +set the hardware in polling mode. This must be implemented only if the hardware +uses proprietary gates or a mechanism slightly different from the HCI standard. +target_from_gate() is another optional entrypoint to return the protocols +corresponding to a proprietary gate. + +On the rx path, the driver is responsible to push incoming HCP frames to HCI +using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling +This must be done from a context that can sleep. + +SHDLC +----- + +Most chips use shdlc to ensure integrity and delivery ordering of the HCP +frames between the host controller (the chip) and hosts (entities connected +to the chip, like the cpu). In order to simplify writing the driver, an shdlc +layer is available for use by the driver. +When used, the driver actually registers with shdlc, and shdlc will register +with HCI. HCI sees shdlc as the driver and thus send its HCP frames +through shdlc->xmit. +SHDLC adds a new execution context (nfc_shdlc_sm_work()) to run its state +machine and handle both its rx and tx path. + +Included Drivers +---------------- + +An HCI based driver for an NXP PN544, connected through I2C bus, and using +shdlc is included. + +Execution Contexts +------------------ + +The execution contexts are the following: +- IRQ handler (IRQH): +fast, cannot sleep. stores incoming frames into an shdlc rx queue + +- SHDLC State Machine worker (SMW) +handles shdlc rx & tx queues. Dispatches HCI cmd responses. + +- HCI Tx Cmd worker (MSGTXWQ) +Serialize execution of HCI commands. Complete execution in case of resp timeout. + +- HCI Rx worker (MSGRXWQ) +Dispatches incoming HCI commands or events. + +- Syscall context from a userspace call (SYSCALL) +Any entrypoint in HCI called from NFC Core + +Workflow executing an HCI command (using shdlc) +----------------------------------------------- + +Executing an HCI command can easily be performed synchronously using the +following API: + +int nfc_hci_send_cmd (struct nfc_hci_dev *hdev, u8 gate, u8 cmd, + const u8 *param, size_t param_len, struct sk_buff **skb) + +The API must be invoked from a context that can sleep. Most of the time, this +will be the syscall context. skb will return the result that was received in +the response. + +Internally, execution is asynchronous. So all this API does is to enqueue the +HCI command, setup a local wait queue on stack, and wait_event() for completion. +The wait is not interruptible because it is guaranteed that the command will +complete after some short timeout anyway. + +MSGTXWQ context will then be scheduled and invoke nfc_hci_msg_tx_work(). +This function will dequeue the next pending command and send its HCP fragments +to the lower layer which happens to be shdlc. It will then start a timer to be +able to complete the command with a timeout error if no response arrive. + +SMW context gets scheduled and invokes nfc_shdlc_sm_work(). This function +handles shdlc framing in and out. It uses the driver xmit to send frames and +receives incoming frames in an skb queue filled from the driver IRQ handler. +SHDLC I(nformation) frames payload are HCP fragments. They are agregated to +form complete HCI frames, which can be a response, command, or event. + +HCI Responses are dispatched immediately from this context to unblock +waiting command execution. Reponse processing involves invoking the completion +callback that was provided by nfc_hci_msg_tx_work() when it sent the command. +The completion callback will then wake the syscall context. + +Workflow receiving an HCI event or command +------------------------------------------ + +HCI commands or events are not dispatched from SMW context. Instead, they are +queued to HCI rx_queue and will be dispatched from HCI rx worker +context (MSGRXWQ). This is done this way to allow a cmd or event handler +to also execute other commands (for example, handling the +NFC_HCI_EVT_TARGET_DISCOVERED event from PN544 requires to issue an +ANY_GET_PARAMETER to the reader A gate to get information on the target +that was discovered). + +Typically, such an event will be propagated to NFC Core from MSGRXWQ context.
Signature · 1 line
1.7.9.1
PATCH 7/18 NFC: The core part should generate the target index
In reply to Samuel OrtizThe target index can be used by userspace to uniquely identify a target and thus should be kept unique, per NFC adapter. Moreover, some protocols do not provide a logical index when discovering new targets, so we have to generate one for them.
For NCI or pn533 to fetch their logical index, we added a logical_idx field to the target structure.
--- include/net/nfc/nfc.h | 2 ++ net/nfc/core.c | 5 +++++ net/nfc/nci/core.c | 2 +- net/nfc/nci/ntf.c | 11 ++++++----- net/nfc/rawsock.c | 6 ++++++ 5 files changed, 20 insertions(+), 6 deletions(-)
include/net/nfc/nfc.h +2 -0
@@ -79,6 +79,7 @@ struct nfc_target {u8 sensf_res_len;u8 sensf_res[NFC_SENSF_RES_MAXSIZE ];u8 hci_reader_gate; +u8 logical_idx; };struct nfc_genl_data {
@@ -88,6 +89,7 @@ struct nfc_genl_data {struct nfc_dev {unsigned idx; +unsigned target_idx;struct nfc_target *targets;int n_targets;int targets_generation;
net/nfc/core.c +5 -0
@@ -428,10 +428,15 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb);int nfc_targets_found (struct nfc_dev *dev,struct nfc_target *targets,int n_targets) { +int i; +pr_debug ("dev_name=%s n_targets=%d\n" ,dev_name (&dev->dev), n_targets); dev->polling = false; +for (i =0 ; i < n_targets; i++) + targets[i].idx = dev->target_idx++; +spin_lock_bh (&dev->targets_lock); dev->targets_generation++;
net/nfc/nci/core.c +1 -1
@@ -477,7 +477,7 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, }if (atomic_read (&ndev->state) ==NCI_W4_HOST_SELECT ) { - param.rf_discovery_id = target->idx; + param.rf_discovery_id = target->logical_idx;if (protocol ==NFC_PROTO_JEWEL ) param.rf_protocol =NCI_RF_PROTOCOL_T1T ;
net/nfc/nci/ntf.c +6 -5
@@ -227,7 +227,7 @@ static void nci_add_new_target(struct nci_dev *ndev,for (i =0 ; i < ndev->n_targets; i++) { target = &ndev->targets[i]; -if (target->idx == ntf->rf_discovery_id) { +if (target->logical_idx == ntf->rf_discovery_id) {/* This target already exists, add the new protocol */ nci_add_new_protocol(ndev, target, ntf->rf_protocol, ntf->rf_tech_and_mode,
@@ -248,10 +248,10 @@ static void nci_add_new_target(struct nci_dev *ndev, ntf->rf_tech_and_mode, &ntf->rf_tech_specific_params);if (!rc) { - target->idx = ntf->rf_discovery_id; + target->logical_idx = ntf->rf_discovery_id; ndev->n_targets++; -pr_debug ("target_idx %d, n_targets %d\n" , target->idx, +pr_debug ("logical idx %d, n_targets %d\n" , target->logical_idx, ndev->n_targets); } }
@@ -372,10 +372,11 @@ static void nci_target_auto_activated(struct nci_dev *ndev,if (rc)return ; - target->idx = ntf->rf_discovery_id; + target->logical_idx = ntf->rf_discovery_id; ndev->n_targets++; -pr_debug ("target_idx %d, n_targets %d\n" , target->idx, ndev->n_targets); +pr_debug ("logical idx %d, n_targets %d\n" , + target->logical_idx, ndev->n_targets);nfc_targets_found (ndev->nfc_dev, ndev->targets, ndev->n_targets); }
net/nfc/rawsock.c +6 -0
@@ -92,6 +92,12 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr, goto error; } +if (addr->target_idx > dev->target_idx -1 || + addr->target_idx < dev->target_idx - dev->n_targets) { + rc = -EINVAL ; + goto error; + } + rc =nfc_activate_target (dev, addr->target_idx, addr->nfc_protocol);if (rc) goto put_dev;
Signature · 1 line
1.7.9.1
PATCH 8/18 NFC: Fix next target_idx type and rename for clarity
In reply to Samuel OrtizFrom: Eric Lapuyade <[email protected]>
--- include/net/nfc/nfc.h | 2 +- net/nfc/core.c | 2 +- net/nfc/rawsock.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-)
include/net/nfc/nfc.h +1 -1
@@ -89,7 +89,7 @@ struct nfc_genl_data {struct nfc_dev {unsigned idx; -unsigned target_idx; +u32 target_next_idx;struct nfc_target *targets;int n_targets;int targets_generation;
net/nfc/core.c +1 -1
@@ -435,7 +435,7 @@ int nfc_targets_found(struct nfc_dev *dev, dev->polling = false;for (i =0 ; i < n_targets; i++) - targets[i].idx = dev->target_idx++; + targets[i].idx = dev->target_next_idx++;spin_lock_bh (&dev->targets_lock);
net/nfc/rawsock.c +2 -2
@@ -92,8 +92,8 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr, goto error; } -if (addr->target_idx > dev->target_idx -1 || - addr->target_idx < dev->target_idx - dev->n_targets) { +if (addr->target_idx > dev->target_next_idx -1 || + addr->target_idx < dev->target_next_idx - dev->n_targets) { rc = -EINVAL ; goto error; }
Signature · 1 line
1.7.9.1
PATCH 9/18 NFC: Changed target activated state logic
In reply to Samuel OrtizFrom: Eric Lapuyade <[email protected]>
--- include/net/nfc/nfc.h | 3 ++- net/nfc/core.c | 24 +++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-)
include/net/nfc/nfc.h +2 -1
@@ -66,6 +66,7 @@ struct nfc_ops {#define NFC_TARGET_IDX_ANY -1#define NFC_MAX_GT_LEN 48 +#define NFC_TARGET_IDX_NONE 0xffffffffstruct nfc_target {u32 idx;
@@ -97,7 +98,7 @@ struct nfc_dev {struct device dev;bool dev_up;bool polling; -bool remote_activated; +u32 activated_target_idx;bool dep_link_up;u32 dep_rf_mode;struct nfc_genl_data genl_data;
net/nfc/core.c +21 -3
@@ -95,7 +95,7 @@ int nfc_dev_down(struct nfc_dev *dev) goto error; } -if (dev->polling || dev->remote_activated) { +if (dev->polling || dev->activated_target_idx !=NFC_TARGET_IDX_NONE ) { rc = -EBUSY ; goto error; }
@@ -211,6 +211,8 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) } rc = dev->ops->dep_link_up (dev, target_index, comm_mode, gb, gb_len); +if (!rc) + dev->activated_target_idx = target_index; error:device_unlock (&dev->dev);
@@ -246,6 +248,7 @@ int nfc_dep_link_down(struct nfc_dev *dev) rc = dev->ops->dep_link_down (dev);if (!rc) { dev->dep_link_up = false; + dev->activated_target_idx =NFC_TARGET_IDX_NONE ;nfc_llcp_mac_is_down (dev);nfc_genl_dep_link_down_event (dev); }
@@ -290,7 +293,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) rc = dev->ops->activate_target (dev, target_idx, protocol);if (!rc) - dev->remote_activated = true; + dev->activated_target_idx = target_idx; error:device_unlock (&dev->dev);
@@ -318,7 +321,7 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx) } dev->ops->deactivate_target (dev, target_idx); - dev->remote_activated = false; + dev->activated_target_idx =NFC_TARGET_IDX_NONE ; error:device_unlock (&dev->dev);
@@ -352,6 +355,18 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, goto error; } +if (dev->activated_target_idx ==NFC_TARGET_IDX_NONE ) { + rc = -ENOTCONN ; +kfree_skb (skb); + goto error; + } + +if (target_idx != dev->activated_target_idx) { + rc = -EADDRNOTAVAIL ; +kfree_skb (skb); + goto error; + } + rc = dev->ops->data_exchange (dev, target_idx, skb, cb, cb_context); error:
@@ -482,6 +497,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) dev->targets_generation++; dev->n_targets--; + dev->activated_target_idx =NFC_TARGET_IDX_NONE ;if (dev->n_targets) { memcpy(&dev->targets[i], &dev->targets[i + 1],
@@ -575,6 +591,8 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,/* first generation must not be 0 */ dev->targets_generation =1 ; + dev->activated_target_idx =NFC_TARGET_IDX_NONE ; +return dev; }EXPORT_SYMBOL (nfc_allocate_device);
Signature · 1 line
1.7.9.1
PATCH 10/18 NFC: Add Core support to generate tag lost event
In reply to Samuel OrtizFrom: Eric Lapuyade <[email protected]>
Some HW/drivers get notifications when a tag moves out of the radio field. This notification is now forwarded to user space through netlink.
--- include/net/nfc/nfc.h | 5 +++ net/nfc/core.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletions(-)
include/net/nfc/nfc.h +5 -0
@@ -62,6 +62,7 @@ struct nfc_ops {int (*data_exchange)(struct nfc_dev *dev,u32 target_idx,struct sk_buff *skb,data_exchange_cb_t cb,void *cb_context); +int (*check_presence)(struct nfc_dev *dev,u32 target_idx); };#define NFC_TARGET_IDX_ANY -1
@@ -107,6 +108,10 @@ struct nfc_dev {int tx_headroom;int tx_tailroom; +struct timer_list check_pres_timer; +struct workqueue_struct *check_pres_wq; +struct work_struct check_pres_work; +struct nfc_ops *ops; };#define to_nfc_dev (_dev) container_of(_dev, struct nfc_dev, dev)
net/nfc/core.c +71 -1
117 lines not on this page · raw message
Signature · 1 line
1.7.9.1
PATCH 11/18 NFC: Dump LLCP frames
In reply to Samuel OrtizAt KERN_DEBUG level.
--- net/nfc/llcp/llcp.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-)
net/nfc/llcp/llcp.c +7 -0
@@ -388,6 +388,9 @@ static void nfc_llcp_tx_work(struct work_struct *work) skb =skb_dequeue (&local->tx_queue);if (skb !=NULL ) {pr_debug ("Sending pending skb\n" ); +print_hex_dump (KERN_DEBUG ,"LLCP Tx: " ,DUMP_PREFIX_OFFSET , +16 ,1 , skb->data, skb->len, true); +nfc_data_exchange (local->dev, local->target_idx, skb, nfc_llcp_recv, local); }else {
@@ -814,6 +817,10 @@ static void nfc_llcp_rx_work(struct work_struct *work)pr_debug ("ptype 0x%x dsap 0x%x ssap 0x%x\n" , ptype, dsap, ssap); +if (ptype !=LLCP_PDU_SYMM ) +print_hex_dump (KERN_DEBUG ,"LLCP Rx: " ,DUMP_PREFIX_OFFSET , +16 ,1 , skb->data, skb->len, true); +switch (ptype) {case LLCP_PDU_SYMM :pr_debug ("SYMM\n" );
Signature · 1 line
1.7.9.1
PATCH 12/18 NFC: No need to apply twice the modulo op to LLCP's recv_n
In reply to Samuel Ortizrecv_n is set properly when receiving an HDLC frame.
--- net/nfc/llcp/commands.c | 2 +- net/nfc/llcp/llcp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
net/nfc/llcp/commands.c +1 -1
@@ -522,7 +522,7 @@ int nfc_llcp_send_rr(struct nfc_llcp_sock *sock)skb_put (skb,LLCP_SEQUENCE_SIZE ); - skb->data[2 ] = sock->recv_n %16 ; + skb->data[2 ] = sock->recv_n;skb_queue_head (&local->tx_queue, skb);
net/nfc/llcp/llcp.c +1 -1
@@ -428,7 +428,7 @@ static u8 nfc_llcp_nr(struct sk_buff *pdu)static void nfc_llcp_set_nrns (struct nfc_llcp_sock *sock,struct sk_buff *pdu) { - pdu->data[2 ] = (sock->send_n <<4 ) | (sock->recv_n %16 ); + pdu->data[2 ] = (sock->send_n <<4 ) | (sock->recv_n); sock->send_n = (sock->send_n +1 ) %16 ; sock->recv_ack_n = (sock->recv_n -1 ) %16 ; }
Signature · 1 line
1.7.9.1
PATCH 13/18 NFC: Fix LLCP TLV building routine
In reply to Samuel OrtizThe if logic could lead to zero length TLVs.
--- net/nfc/llcp/commands.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
net/nfc/llcp/commands.c +1 -1
@@ -102,7 +102,7 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length) length = llcp_tlv_length[type];if (length ==0 && value_length ==0 )return NULL ; -else +else if (length ==0 ) length = value_length; *tlv_length =2 + length;
Signature · 1 line
1.7.9.1
PATCH 14/18 NFC: Call llcp_add_header properly when sending LLCP DM or DISC
In reply to Samuel Ortizdsap and ssap were swapped when sending DN or DISC.
--- net/nfc/llcp/commands.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
net/nfc/llcp/commands.c +2 -2
@@ -248,7 +248,7 @@ int nfc_llcp_disconnect(struct nfc_llcp_sock *sock)skb_reserve (skb, dev->tx_headroom +NFC_HEADER_SIZE ); - skb =llcp_add_header (skb, sock->ssap, sock->dsap,LLCP_PDU_DISC ); + skb =llcp_add_header (skb, sock->dsap, sock->ssap,LLCP_PDU_DISC );skb_queue_tail (&local->tx_queue, skb);
@@ -416,7 +416,7 @@ int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)skb_reserve (skb, dev->tx_headroom +NFC_HEADER_SIZE ); - skb =llcp_add_header (skb, ssap, dsap,LLCP_PDU_DM ); + skb =llcp_add_header (skb, dsap, ssap,LLCP_PDU_DM );memcpy (skb_put (skb,1 ), &reason,1 );
Signature · 1 line
1.7.9.1
PATCH 15/18 NFC: Convert pn533 from tasklet to workqueues
In reply to Samuel OrtizThere is no need for soft IRQ contexts, and workqueues are more flexible.
--- drivers/nfc/pn533.c | 86 ++++++++++++++++++++++++++++---------------------- 1 files changed, 48 insertions(+), 38 deletions(-)
drivers/nfc/pn533.c +48 -38
@@ -266,9 +266,10 @@ struct pn533 {int in_maxlen;struct pn533_frame *in_frame; -struct tasklet_struct tasklet; -struct pn533_frame *tklt_in_frame; -int tklt_in_error; +struct workqueue_struct *wq; +struct work_struct cmd_work; +struct pn533_frame *wq_in_frame; +int wq_in_error;pn533_cmd_complete_t cmd_complete;void *cmd_complete_arg;
@@ -383,15 +384,21 @@ static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd)return (PN533_FRAME_CMD (frame) ==PN533_CMD_RESPONSE (cmd)); } -static void pn533_tasklet_cmd_complete (unsigned long arg) + +static void pn533_wq_cmd_complete (struct work_struct *work) { -struct pn533 *dev = (struct pn533 *) arg; -struct pn533_frame *in_frame = dev->tklt_in_frame; + struct pn533 *dev = container_of(work, struct pn533, cmd_work); +struct pn533_frame *in_frame;int rc; -if (dev->tklt_in_error) +if (dev ==NULL ) +return ; + + in_frame = dev->wq_in_frame; + +if (dev->wq_in_error) rc = dev->cmd_complete (dev, dev->cmd_complete_arg,NULL , - dev->tklt_in_error); + dev->wq_in_error);else rc = dev->cmd_complete(dev, dev->cmd_complete_arg, PN533_FRAME_CMD_PARAMS_PTR(in_frame),
@@ -406,7 +413,7 @@ static void pn533_recv_response(struct urb *urb)struct pn533 *dev = urb->context;struct pn533_frame *in_frame; - dev->tklt_in_frame =NULL ; + dev->wq_in_frame =NULL ;switch (urb->status) {case 0 :
@@ -417,36 +424,36 @@ static void pn533_recv_response(struct urb *urb)case -ESHUTDOWN :nfc_dev_dbg (&dev->interface->dev,"Urb shutting down with" " status: %d" , urb->status); - dev->tklt_in_error = urb->status; - goto sched_tasklet; + dev->wq_in_error = urb->status; + goto sched_wq;default :nfc_dev_err (&dev->interface->dev,"Nonzero urb status received:" " %d" , urb->status); - dev->tklt_in_error = urb->status; - goto sched_tasklet; + dev->wq_in_error = urb->status; + goto sched_wq; } in_frame = dev->in_urb->transfer_buffer;if (!pn533_rx_frame_is_valid (in_frame)) {nfc_dev_err (&dev->interface->dev,"Received an invalid frame" ); - dev->tklt_in_error = -EIO ; - goto sched_tasklet; + dev->wq_in_error = -EIO ; + goto sched_wq; }if (!pn533_rx_frame_is_cmd_response (in_frame, dev->cmd)) {nfc_dev_err (&dev->interface->dev,"The received frame is not " "response to the last command" ); - dev->tklt_in_error = -EIO ; - goto sched_tasklet; + dev->wq_in_error = -EIO ; + goto sched_wq; }nfc_dev_dbg (&dev->interface->dev,"Received a valid frame" ); - dev->tklt_in_error =0 ; - dev->tklt_in_frame = in_frame; + dev->wq_in_error =0 ; + dev->wq_in_frame = in_frame; -sched_tasklet: -tasklet_schedule (&dev->tasklet); +sched_wq: +queue_work (dev->wq, &dev->cmd_work); }static int pn533_submit_urb_for_response (struct pn533 *dev,gfp_t flags)
@@ -471,21 +478,21 @@ static void pn533_recv_ack(struct urb *urb)case -ESHUTDOWN :nfc_dev_dbg (&dev->interface->dev,"Urb shutting down with" " status: %d" , urb->status); - dev->tklt_in_error = urb->status; - goto sched_tasklet; + dev->wq_in_error = urb->status; + goto sched_wq;default :nfc_dev_err (&dev->interface->dev,"Nonzero urb status received:" " %d" , urb->status); - dev->tklt_in_error = urb->status; - goto sched_tasklet; + dev->wq_in_error = urb->status; + goto sched_wq; } in_frame = dev->in_urb->transfer_buffer;if (!pn533_rx_frame_is_ack (in_frame)) {nfc_dev_err (&dev->interface->dev,"Received an invalid ack" ); - dev->tklt_in_error = -EIO ; - goto sched_tasklet; + dev->wq_in_error = -EIO ; + goto sched_wq; }nfc_dev_dbg (&dev->interface->dev,"Received a valid ack" );
@@ -494,15 +501,15 @@ static void pn533_recv_ack(struct urb *urb)if (rc) {nfc_dev_err (&dev->interface->dev,"usb_submit_urb failed with" " result %d" , rc); - dev->tklt_in_error = rc; - goto sched_tasklet; + dev->wq_in_error = rc; + goto sched_wq; }return ; -sched_tasklet: - dev->tklt_in_frame =NULL ; -tasklet_schedule (&dev->tasklet); +sched_wq: + dev->wq_in_frame =NULL ; +queue_work (dev->wq, &dev->cmd_work); }static int pn533_submit_urb_for_ack (struct pn533 *dev,gfp_t flags)
@@ -1668,7 +1675,10 @@ static int pn533_probe(struct usb_interface *interface,NULL ,0 , pn533_send_complete, dev); -tasklet_init (&dev->tasklet, pn533_tasklet_cmd_complete, (ulong )dev); +INIT_WORK (&dev->cmd_work, pn533_wq_cmd_complete); + dev->wq =create_singlethread_workqueue ("pn533" ); +if (dev->wq ==NULL ) + goto error;usb_set_intfdata (interface, dev);
@@ -1678,7 +1688,7 @@ static int pn533_probe(struct usb_interface *interface, rc =pn533_send_cmd_frame_sync (dev, dev->out_frame, dev->in_frame, dev->in_maxlen);if (rc) - goto kill_tasklet; + goto destroy_wq; fw_ver = (struct pn533_fw_version *)PN533_FRAME_CMD_PARAMS_PTR (dev->in_frame);
@@ -1694,7 +1704,7 @@ static int pn533_probe(struct usb_interface *interface,PN533_CMD_DATAEXCH_HEAD_LEN , PN533_FRAME_TAIL_SIZE);if (!dev->nfc_dev) - goto kill_tasklet; + goto destroy_wq;nfc_set_parent_dev (dev->nfc_dev, &interface->dev);nfc_set_drvdata (dev->nfc_dev, dev);
@@ -1720,8 +1730,8 @@ static int pn533_probe(struct usb_interface *interface, free_nfc_dev:nfc_free_device (dev->nfc_dev); -kill_tasklet: -tasklet_kill (&dev->tasklet); +destroy_wq: +destroy_workqueue (dev->wq); error:kfree (dev->in_frame);usb_free_urb (dev->in_urb);
@@ -1744,7 +1754,7 @@ static void pn533_disconnect(struct usb_interface *interface)usb_kill_urb (dev->in_urb);usb_kill_urb (dev->out_urb); -tasklet_kill (&dev->tasklet); +destroy_workqueue (dev->wq);kfree (dev->in_frame);usb_free_urb (dev->in_urb);
Signature · 1 line
1.7.9.1
PATCH 16/18 NFC: pn533 Rx chaining support
In reply to Samuel OrtizWhen buffers on the receiption path exceed 262 bytes, the pn533 uses a chaining mechanism where the initiator has to send NULL data frames to fetch the remaining frames.
We do that from a workqueue context while holding the cmd lock. Once the MI bit is gone, we aggregate the queued received skbs.
--- drivers/nfc/pn533.c | 144 +++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 128 insertions(+), 16 deletions(-)
drivers/nfc/pn533.c +128 -16
@@ -266,8 +266,11 @@ struct pn533 {int in_maxlen;struct pn533_frame *in_frame; +struct sk_buff_head resp_q; +struct workqueue_struct *wq;struct work_struct cmd_work; +struct work_struct mi_work;struct pn533_frame *wq_in_frame;int wq_in_error;
@@ -1256,6 +1259,8 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) dev->tgt_active_prot =0 ; +skb_queue_purge (&dev->resp_q); +pn533_tx_frame_init (dev->out_frame,PN533_CMD_IN_RELEASE ); tg =1 ;
@@ -1454,11 +1459,49 @@ struct pn533_data_exchange_arg {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 ; + +nfc_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; + +nfc_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,u8 *params,int params_len) {struct pn533_data_exchange_arg *arg = _arg; -struct sk_buff *skb_resp = arg->skb_resp; +struct sk_buff *skb =NULL , *skb_resp = arg->skb_resp;struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;int err =0 ;u8 status;
@@ -1466,15 +1509,13 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,nfc_dev_dbg (&dev->interface->dev,"%s" , __func__); -dev_kfree_skb_irq (arg->skb_out); +dev_kfree_skb (arg->skb_out);if (params_len <0 ) {/* error */ err = params_len; goto error; } -skb_put (skb_resp,PN533_FRAME_SIZE (in_frame)); - status = params[0 ]; cmd_ret = status &PN533_CMD_RET_MASK ;
@@ -1485,25 +1526,27 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, goto error; } +skb_put (skb_resp,PN533_FRAME_SIZE (in_frame)); +skb_pull (skb_resp,PN533_CMD_DATAEXCH_HEAD_LEN ); +skb_trim (skb_resp, skb_resp->len -PN533_FRAME_TAIL_SIZE ); +skb_queue_tail (&dev->resp_q, skb_resp); +if (status &PN533_CMD_MI_MASK ) { -/* TODO: Implement support to multi-part data exchange */ -nfc_dev_err (&dev->interface->dev,"Multi-part message not yet" -" supported" ); -/* Prevent the other messages from controller */ -pn533_send_ack (dev,GFP_ATOMIC ); - err = -ENOSYS ; - goto error; +queue_work (dev->wq, &dev->mi_work); +return -EINPROGRESS ; } -skb_pull (skb_resp,PN533_CMD_DATAEXCH_HEAD_LEN ); -skb_trim (skb_resp, skb_resp->len -PN533_FRAME_TAIL_SIZE ); + skb =pn533_build_response (dev); +if (skb ==NULL ) + goto error; - arg->cb (arg->cb_context, skb_resp,0 ); + arg->cb (arg->cb_context, skb,0 );kfree (arg);return 0 ; error: -dev_kfree_skb_irq (skb_resp); +skb_queue_purge (&dev->resp_q); +dev_kfree_skb (skb_resp); arg->cb (arg->cb_context,NULL , err);kfree (arg);return 0 ;
@@ -1578,6 +1621,68 @@ error:return rc; } +static void pn533_wq_mi_recv (struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, mi_work); +struct sk_buff *skb_cmd; +struct pn533_data_exchange_arg *arg = dev->cmd_complete_arg; +struct pn533_frame *out_frame, *in_frame; +struct sk_buff *skb_resp; +int skb_resp_len; +int rc; + +nfc_dev_dbg (&dev->interface->dev,"%s" , __func__); + +/* This is a zero payload size skb */ + skb_cmd =alloc_skb (PN533_CMD_DATAEXCH_HEAD_LEN +PN533_FRAME_TAIL_SIZE , +GFP_KERNEL ); +if (skb_cmd ==NULL ) + goto error_cmd; + +skb_reserve (skb_cmd,PN533_CMD_DATAEXCH_HEAD_LEN ); + + rc =pn533_data_exchange_tx_frame (dev, skb_cmd); +if (rc) + goto error_frame; + + skb_resp_len =PN533_CMD_DATAEXCH_HEAD_LEN + +PN533_CMD_DATAEXCH_DATA_MAXLEN + +PN533_FRAME_TAIL_SIZE ; + skb_resp =alloc_skb (skb_resp_len,GFP_KERNEL ); +if (!skb_resp) { + rc = -ENOMEM ; + goto error_frame; + } + + in_frame = (struct pn533_frame *) skb_resp->data; + out_frame = (struct pn533_frame *) skb_cmd->data; + + arg->skb_resp = skb_resp; + arg->skb_out = skb_cmd; + + rc =__pn533_send_cmd_frame_async (dev, out_frame, in_frame, + skb_resp_len, + pn533_data_exchange_complete, + dev->cmd_complete_arg,GFP_KERNEL ); +if (!rc) +return ; + +nfc_dev_err (&dev->interface->dev,"Error %d when trying to" +" perform data_exchange" , rc); + +kfree_skb (skb_resp); + +error_frame: +kfree_skb (skb_cmd); + +error_cmd: +pn533_send_ack (dev,GFP_KERNEL ); + +kfree (arg); + +up (&dev->cmd_lock); +} +static int pn533_set_configuration (struct pn533 *dev,u8 cfgitem,u8 *cfgdata,u8 cfgdata_len) {
@@ -1676,10 +1781,15 @@ static int pn533_probe(struct usb_interface *interface, pn533_send_complete, dev);INIT_WORK (&dev->cmd_work, pn533_wq_cmd_complete); - dev->wq =create_singlethread_workqueue ("pn533" ); +INIT_WORK (&dev->mi_work, pn533_wq_mi_recv); + dev->wq =alloc_workqueue ("pn533" , +WQ_NON_REENTRANT |WQ_UNBOUND |WQ_MEM_RECLAIM , +1 );if (dev->wq ==NULL ) goto error; +skb_queue_head_init (&dev->resp_q); +usb_set_intfdata (interface, dev);pn533_tx_frame_init (dev->out_frame,PN533_CMD_GET_FIRMWARE_VERSION );
@@ -1756,6 +1866,8 @@ static void pn533_disconnect(struct usb_interface *interface)destroy_workqueue (dev->wq); +skb_queue_purge (&dev->resp_q); +kfree (dev->in_frame);usb_free_urb (dev->in_urb);kfree (dev->out_frame);
Signature · 1 line
1.7.9.1
PATCH 17/18 NFC: Add MIUX to the local LLCP general bytes
In reply to Samuel Ortiz--- net/nfc/llcp/llcp.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
net/nfc/llcp/llcp.c +10 -0
@@ -307,6 +307,8 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)u8 *gb_cur, *version_tlv, version, version_length;u8 *lto_tlv, lto, lto_length;u8 *wks_tlv, wks_length; +u8 *miux_tlv, miux_length; +__be16 miux;u8 gb_len =0 ; version =LLCP_VERSION_11 ;
@@ -324,6 +326,11 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) &wks_length); gb_len += wks_length; + miux =cpu_to_be16 (LLCP_MAX_MIUX ); + miux_tlv =nfc_llcp_build_tlv (LLCP_TLV_MIUX , (u8 *)&miux,0 , + &miux_length); + gb_len += miux_length; + gb_len +=ARRAY_SIZE (llcp_magic);if (gb_len >NFC_MAX_GT_LEN ) {
@@ -345,6 +352,9 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)memcpy (gb_cur, wks_tlv, wks_length); gb_cur += wks_length; +memcpy (gb_cur, miux_tlv, miux_length); + gb_cur += miux_length; +kfree (version_tlv);kfree (lto_tlv);
Signature · 1 line
1.7.9.1
PATCH 18/18 NFC: Fix LLCP link timeout typo
In reply to Samuel OrtizWe were sending the LTO TLV as a version TLV instead of the actual link timeout one.
--- net/nfc/llcp/llcp.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
net/nfc/llcp/llcp.c +1 -1
@@ -318,7 +318,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)/* 1500 ms */ lto =150 ; - lto_tlv =nfc_llcp_build_tlv (LLCP_TLV_VERSION , <o,1 , <o_length); + lto_tlv =nfc_llcp_build_tlv (LLCP_TLV_LTO , <o,1 , <o_length); gb_len += lto_length;pr_debug ("Local wks 0x%lx\n" , local->local_wks);
Signature · 1 line
1.7.9.1