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 | |
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>
-rw-r--r-- | include/net/nfc/nci_core.h | 14 | ||||
-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 |
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 | ||
67 | struct nci_dev; | 67 | struct nci_dev; |
68 | 68 | ||
69 | struct 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 | |||
69 | struct nci_ops { | 75 | struct 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 | ||
94 | struct nci_conn_info { | 104 | struct 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 | ||
321 | void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb); | 331 | void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb); |
322 | void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb); | 332 | void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb); |
333 | int nci_prop_rsp_packet(struct nci_dev *ndev, __u16 opcode, | ||
334 | struct sk_buff *skb); | ||
335 | int nci_prop_ntf_packet(struct nci_dev *ndev, __u16 opcode, | ||
336 | struct sk_buff *skb); | ||
323 | void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb); | 337 | void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb); |
324 | int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload); | 338 | int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload); |
325 | int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb); | 339 | int 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 */ | ||
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 */ |