aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2015-06-06 07:16:37 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2015-06-08 18:34:20 -0400
commitb6355e972aaab0173ce11a1650e7dba67f820918 (patch)
tree309ff674278ea4829fbe6970e513338cbaf9fde3
parent2622e2a03cd7320f57a4f5171c242dccdab035dd (diff)
NFC: nci: Handle proprietary response and notifications
Allow for drivers to explicitly define handlers for each proprietary notifications and responses they expect to support. Reviewed-by: Christophe Ricard <christophe-h.ricard@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--include/net/nfc/nci_core.h14
-rw-r--r--net/nfc/nci/core.c52
-rw-r--r--net/nfc/nci/ntf.c10
-rw-r--r--net/nfc/nci/rsp.c10
4 files changed, 86 insertions, 0 deletions
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
index d4dcc7199fd7..c49688c09853 100644
--- a/include/net/nfc/nci_core.h
+++ b/include/net/nfc/nci_core.h
@@ -66,6 +66,12 @@ enum nci_state {
66 66
67struct nci_dev; 67struct nci_dev;
68 68
69struct nci_prop_ops {
70 __u16 opcode;
71 int (*rsp)(struct nci_dev *dev, struct sk_buff *skb);
72 int (*ntf)(struct nci_dev *dev, struct sk_buff *skb);
73};
74
69struct nci_ops { 75struct nci_ops {
70 int (*open)(struct nci_dev *ndev); 76 int (*open)(struct nci_dev *ndev);
71 int (*close)(struct nci_dev *ndev); 77 int (*close)(struct nci_dev *ndev);
@@ -84,12 +90,16 @@ struct nci_ops {
84 struct sk_buff *skb); 90 struct sk_buff *skb);
85 void (*hci_cmd_received)(struct nci_dev *ndev, u8 pipe, u8 cmd, 91 void (*hci_cmd_received)(struct nci_dev *ndev, u8 pipe, u8 cmd,
86 struct sk_buff *skb); 92 struct sk_buff *skb);
93
94 struct nci_prop_ops *prop_ops;
95 size_t n_prop_ops;
87}; 96};
88 97
89#define NCI_MAX_SUPPORTED_RF_INTERFACES 4 98#define NCI_MAX_SUPPORTED_RF_INTERFACES 4
90#define NCI_MAX_DISCOVERED_TARGETS 10 99#define NCI_MAX_DISCOVERED_TARGETS 10
91#define NCI_MAX_NUM_NFCEE 255 100#define NCI_MAX_NUM_NFCEE 255
92#define NCI_MAX_CONN_ID 7 101#define NCI_MAX_CONN_ID 7
102#define NCI_MAX_PROPRIETARY_CMD 64
93 103
94struct nci_conn_info { 104struct nci_conn_info {
95 struct list_head list; 105 struct list_head list;
@@ -320,6 +330,10 @@ static inline void *nci_get_drvdata(struct nci_dev *ndev)
320 330
321void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb); 331void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb);
322void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb); 332void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb);
333int nci_prop_rsp_packet(struct nci_dev *ndev, __u16 opcode,
334 struct sk_buff *skb);
335int nci_prop_ntf_packet(struct nci_dev *ndev, __u16 opcode,
336 struct sk_buff *skb);
323void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb); 337void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb);
324int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload); 338int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload);
325int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb); 339int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb);
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 49ff32106080..56d57c93ea1a 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -28,6 +28,7 @@
28#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ 28#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
29 29
30#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/kernel.h>
31#include <linux/types.h> 32#include <linux/types.h>
32#include <linux/workqueue.h> 33#include <linux/workqueue.h>
33#include <linux/completion.h> 34#include <linux/completion.h>
@@ -961,6 +962,14 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops,
961 return NULL; 962 return NULL;
962 963
963 ndev->ops = ops; 964 ndev->ops = ops;
965
966 if (ops->n_prop_ops > NCI_MAX_PROPRIETARY_CMD) {
967 pr_err("Too many proprietary commands: %zd\n",
968 ops->n_prop_ops);
969 ops->prop_ops = NULL;
970 ops->n_prop_ops = 0;
971 }
972
964 ndev->tx_headroom = tx_headroom; 973 ndev->tx_headroom = tx_headroom;
965 ndev->tx_tailroom = tx_tailroom; 974 ndev->tx_tailroom = tx_tailroom;
966 init_completion(&ndev->req_completion); 975 init_completion(&ndev->req_completion);
@@ -1165,6 +1174,49 @@ int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload)
1165 return 0; 1174 return 0;
1166} 1175}
1167 1176
1177/* Proprietary commands API */
1178static struct nci_prop_ops *prop_cmd_lookup(struct nci_dev *ndev,
1179 __u16 opcode)
1180{
1181 size_t i;
1182 struct nci_prop_ops *prop_op;
1183
1184 if (!ndev->ops->prop_ops || !ndev->ops->n_prop_ops)
1185 return NULL;
1186
1187 for (i = 0; i < ndev->ops->n_prop_ops; i++) {
1188 prop_op = &ndev->ops->prop_ops[i];
1189 if (prop_op->opcode == opcode)
1190 return prop_op;
1191 }
1192
1193 return NULL;
1194}
1195
1196int nci_prop_rsp_packet(struct nci_dev *ndev, __u16 rsp_opcode,
1197 struct sk_buff *skb)
1198{
1199 struct nci_prop_ops *prop_op;
1200
1201 prop_op = prop_cmd_lookup(ndev, rsp_opcode);
1202 if (!prop_op || !prop_op->rsp)
1203 return -ENOTSUPP;
1204
1205 return prop_op->rsp(ndev, skb);
1206}
1207
1208int nci_prop_ntf_packet(struct nci_dev *ndev, __u16 ntf_opcode,
1209 struct sk_buff *skb)
1210{
1211 struct nci_prop_ops *prop_op;
1212
1213 prop_op = prop_cmd_lookup(ndev, ntf_opcode);
1214 if (!prop_op || !prop_op->ntf)
1215 return -ENOTSUPP;
1216
1217 return prop_op->ntf(ndev, skb);
1218}
1219
1168/* ---- NCI TX Data worker thread ---- */ 1220/* ---- NCI TX Data worker thread ---- */
1169 1221
1170static void nci_tx_work(struct work_struct *work) 1222static void nci_tx_work(struct work_struct *work)
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
index 3218071072ac..5d1c2e391c56 100644
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -758,6 +758,15 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
758 /* strip the nci control header */ 758 /* strip the nci control header */
759 skb_pull(skb, NCI_CTRL_HDR_SIZE); 759 skb_pull(skb, NCI_CTRL_HDR_SIZE);
760 760
761 if (nci_opcode_gid(ntf_opcode) == NCI_GID_PROPRIETARY) {
762 if (nci_prop_ntf_packet(ndev, ntf_opcode, skb)) {
763 pr_err("unsupported ntf opcode 0x%x\n",
764 ntf_opcode);
765 }
766
767 goto end;
768 }
769
761 switch (ntf_opcode) { 770 switch (ntf_opcode) {
762 case NCI_OP_CORE_CONN_CREDITS_NTF: 771 case NCI_OP_CORE_CONN_CREDITS_NTF:
763 nci_core_conn_credits_ntf_packet(ndev, skb); 772 nci_core_conn_credits_ntf_packet(ndev, skb);
@@ -796,5 +805,6 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
796 break; 805 break;
797 } 806 }
798 807
808end:
799 kfree_skb(skb); 809 kfree_skb(skb);
800} 810}
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c
index 02486bc2ceea..408bd8f857ab 100644
--- a/net/nfc/nci/rsp.c
+++ b/net/nfc/nci/rsp.c
@@ -296,6 +296,15 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
296 /* strip the nci control header */ 296 /* strip the nci control header */
297 skb_pull(skb, NCI_CTRL_HDR_SIZE); 297 skb_pull(skb, NCI_CTRL_HDR_SIZE);
298 298
299 if (nci_opcode_gid(rsp_opcode) == NCI_GID_PROPRIETARY) {
300 if (nci_prop_rsp_packet(ndev, rsp_opcode, skb) == -ENOTSUPP) {
301 pr_err("unsupported rsp opcode 0x%x\n",
302 rsp_opcode);
303 }
304
305 goto end;
306 }
307
299 switch (rsp_opcode) { 308 switch (rsp_opcode) {
300 case NCI_OP_CORE_RESET_RSP: 309 case NCI_OP_CORE_RESET_RSP:
301 nci_core_reset_rsp_packet(ndev, skb); 310 nci_core_reset_rsp_packet(ndev, skb);
@@ -346,6 +355,7 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
346 break; 355 break;
347 } 356 }
348 357
358end:
349 kfree_skb(skb); 359 kfree_skb(skb);
350 360
351 /* trigger the next cmd */ 361 /* trigger the next cmd */