diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2015-06-06 07:16:37 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2015-06-08 18:34:20 -0400 |
commit | b6355e972aaab0173ce11a1650e7dba67f820918 (patch) | |
tree | 309ff674278ea4829fbe6970e513338cbaf9fde3 /net/nfc | |
parent | 2622e2a03cd7320f57a4f5171c242dccdab035dd (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>
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/nci/core.c | 52 | ||||
-rw-r--r-- | net/nfc/nci/ntf.c | 10 | ||||
-rw-r--r-- | net/nfc/nci/rsp.c | 10 |
3 files changed, 72 insertions, 0 deletions
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 */ | ||
1178 | static 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 | |||
1196 | int 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 | |||
1208 | int 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 | ||
1170 | static void nci_tx_work(struct work_struct *work) | 1222 | static 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 | ||
808 | end: | ||
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 | ||
358 | end: | ||
349 | kfree_skb(skb); | 359 | kfree_skb(skb); |
350 | 360 | ||
351 | /* trigger the next cmd */ | 361 | /* trigger the next cmd */ |