1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26a2968aaSIlan Elias /*
36a2968aaSIlan Elias * The NFC Controller Interface is the communication protocol between an
46a2968aaSIlan Elias * NFC Controller (NFCC) and a Device Host (DH).
56a2968aaSIlan Elias *
66a2968aaSIlan Elias * Copyright (C) 2011 Texas Instruments, Inc.
76a2968aaSIlan Elias *
86a2968aaSIlan Elias * Written by Ilan Elias <ilane@ti.com>
96a2968aaSIlan Elias *
106a2968aaSIlan Elias * Acknowledgements:
116a2968aaSIlan Elias * This file is based on hci_event.c, which was written
126a2968aaSIlan Elias * by Maxim Krasnyansky.
136a2968aaSIlan Elias */
146a2968aaSIlan Elias
1552858b51SSamuel Ortiz #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
16ed1e0ad8SJoe Perches
176a2968aaSIlan Elias #include <linux/types.h>
186a2968aaSIlan Elias #include <linux/interrupt.h>
196a2968aaSIlan Elias #include <linux/bitops.h>
206a2968aaSIlan Elias #include <linux/skbuff.h>
216a2968aaSIlan Elias
226a2968aaSIlan Elias #include "../nfc.h"
236a2968aaSIlan Elias #include <net/nfc/nci.h>
246a2968aaSIlan Elias #include <net/nfc/nci_core.h>
256a2968aaSIlan Elias
266a2968aaSIlan Elias /* Handle NCI Response packets */
276a2968aaSIlan Elias
nci_core_reset_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)28ddecf555SKrzysztof Kozlowski static void nci_core_reset_rsp_packet(struct nci_dev *ndev,
29ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
306a2968aaSIlan Elias {
31ddecf555SKrzysztof Kozlowski const struct nci_core_reset_rsp *rsp = (void *)skb->data;
326a2968aaSIlan Elias
3324bf3304SJoe Perches pr_debug("status 0x%x\n", rsp->status);
346a2968aaSIlan Elias
35bcd684aaSBongsu Jeon /* Handle NCI 1.x ver */
36bcd684aaSBongsu Jeon if (skb->len != 1) {
37e8c0dacdSIlan Elias if (rsp->status == NCI_STATUS_OK) {
386a2968aaSIlan Elias ndev->nci_ver = rsp->nci_ver;
3920c239c1SJoe Perches pr_debug("nci_ver 0x%x, config_status 0x%x\n",
40e8c0dacdSIlan Elias rsp->nci_ver, rsp->config_status);
41e8c0dacdSIlan Elias }
426a2968aaSIlan Elias
436a2968aaSIlan Elias nci_req_complete(ndev, rsp->status);
446a2968aaSIlan Elias }
45bcd684aaSBongsu Jeon }
466a2968aaSIlan Elias
nci_core_init_rsp_packet_v1(struct nci_dev * ndev,const struct sk_buff * skb)47ddecf555SKrzysztof Kozlowski static u8 nci_core_init_rsp_packet_v1(struct nci_dev *ndev,
48ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
496a2968aaSIlan Elias {
50ddecf555SKrzysztof Kozlowski const struct nci_core_init_rsp_1 *rsp_1 = (void *)skb->data;
51ddecf555SKrzysztof Kozlowski const struct nci_core_init_rsp_2 *rsp_2;
526a2968aaSIlan Elias
5324bf3304SJoe Perches pr_debug("status 0x%x\n", rsp_1->status);
546a2968aaSIlan Elias
556a2968aaSIlan Elias if (rsp_1->status != NCI_STATUS_OK)
56bcd684aaSBongsu Jeon return rsp_1->status;
576a2968aaSIlan Elias
586a2968aaSIlan Elias ndev->nfcc_features = __le32_to_cpu(rsp_1->nfcc_features);
596a2968aaSIlan Elias ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces;
606a2968aaSIlan Elias
616a2968aaSIlan Elias ndev->num_supported_rf_interfaces =
62bcd684aaSBongsu Jeon min((int)ndev->num_supported_rf_interfaces,
63bcd684aaSBongsu Jeon NCI_MAX_SUPPORTED_RF_INTERFACES);
646a2968aaSIlan Elias
656a2968aaSIlan Elias memcpy(ndev->supported_rf_interfaces,
666a2968aaSIlan Elias rsp_1->supported_rf_interfaces,
676a2968aaSIlan Elias ndev->num_supported_rf_interfaces);
686a2968aaSIlan Elias
69e8c0dacdSIlan Elias rsp_2 = (void *) (skb->data + 6 + rsp_1->num_supported_rf_interfaces);
706a2968aaSIlan Elias
71eb9bc6e9SSamuel Ortiz ndev->max_logical_connections = rsp_2->max_logical_connections;
726a2968aaSIlan Elias ndev->max_routing_table_size =
736a2968aaSIlan Elias __le16_to_cpu(rsp_2->max_routing_table_size);
74e8c0dacdSIlan Elias ndev->max_ctrl_pkt_payload_len =
75e8c0dacdSIlan Elias rsp_2->max_ctrl_pkt_payload_len;
76e8c0dacdSIlan Elias ndev->max_size_for_large_params =
77e8c0dacdSIlan Elias __le16_to_cpu(rsp_2->max_size_for_large_params);
78e8c0dacdSIlan Elias ndev->manufact_id =
79e8c0dacdSIlan Elias rsp_2->manufact_id;
80e8c0dacdSIlan Elias ndev->manufact_specific_info =
81e8c0dacdSIlan Elias __le32_to_cpu(rsp_2->manufact_specific_info);
82e8c0dacdSIlan Elias
83bcd684aaSBongsu Jeon return NCI_STATUS_OK;
84bcd684aaSBongsu Jeon }
85bcd684aaSBongsu Jeon
nci_core_init_rsp_packet_v2(struct nci_dev * ndev,const struct sk_buff * skb)86ddecf555SKrzysztof Kozlowski static u8 nci_core_init_rsp_packet_v2(struct nci_dev *ndev,
87ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
88bcd684aaSBongsu Jeon {
89ddecf555SKrzysztof Kozlowski const struct nci_core_init_rsp_nci_ver2 *rsp = (void *)skb->data;
90ddecf555SKrzysztof Kozlowski const u8 *supported_rf_interface = rsp->supported_rf_interfaces;
91bcd684aaSBongsu Jeon u8 rf_interface_idx = 0;
92bcd684aaSBongsu Jeon u8 rf_extension_cnt = 0;
93bcd684aaSBongsu Jeon
94bcd684aaSBongsu Jeon pr_debug("status %x\n", rsp->status);
95bcd684aaSBongsu Jeon
96bcd684aaSBongsu Jeon if (rsp->status != NCI_STATUS_OK)
97bcd684aaSBongsu Jeon return rsp->status;
98bcd684aaSBongsu Jeon
99bcd684aaSBongsu Jeon ndev->nfcc_features = __le32_to_cpu(rsp->nfcc_features);
100bcd684aaSBongsu Jeon ndev->num_supported_rf_interfaces = rsp->num_supported_rf_interfaces;
101bcd684aaSBongsu Jeon
102bcd684aaSBongsu Jeon ndev->num_supported_rf_interfaces =
103bcd684aaSBongsu Jeon min((int)ndev->num_supported_rf_interfaces,
104bcd684aaSBongsu Jeon NCI_MAX_SUPPORTED_RF_INTERFACES);
105bcd684aaSBongsu Jeon
106bcd684aaSBongsu Jeon while (rf_interface_idx < ndev->num_supported_rf_interfaces) {
107bcd684aaSBongsu Jeon ndev->supported_rf_interfaces[rf_interface_idx++] = *supported_rf_interface++;
108bcd684aaSBongsu Jeon
109bcd684aaSBongsu Jeon /* skip rf extension parameters */
110bcd684aaSBongsu Jeon rf_extension_cnt = *supported_rf_interface++;
111bcd684aaSBongsu Jeon supported_rf_interface += rf_extension_cnt;
112bcd684aaSBongsu Jeon }
113bcd684aaSBongsu Jeon
114bcd684aaSBongsu Jeon ndev->max_logical_connections = rsp->max_logical_connections;
115bcd684aaSBongsu Jeon ndev->max_routing_table_size =
116bcd684aaSBongsu Jeon __le16_to_cpu(rsp->max_routing_table_size);
117bcd684aaSBongsu Jeon ndev->max_ctrl_pkt_payload_len =
118bcd684aaSBongsu Jeon rsp->max_ctrl_pkt_payload_len;
119bcd684aaSBongsu Jeon ndev->max_size_for_large_params = NCI_MAX_LARGE_PARAMS_NCI_v2;
120bcd684aaSBongsu Jeon
121bcd684aaSBongsu Jeon return NCI_STATUS_OK;
122bcd684aaSBongsu Jeon }
123bcd684aaSBongsu Jeon
nci_core_init_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)124ddecf555SKrzysztof Kozlowski static void nci_core_init_rsp_packet(struct nci_dev *ndev, const struct sk_buff *skb)
125bcd684aaSBongsu Jeon {
126bcd684aaSBongsu Jeon u8 status = 0;
127bcd684aaSBongsu Jeon
128bcd684aaSBongsu Jeon if (!(ndev->nci_ver & NCI_VER_2_MASK))
129bcd684aaSBongsu Jeon status = nci_core_init_rsp_packet_v1(ndev, skb);
130bcd684aaSBongsu Jeon else
131bcd684aaSBongsu Jeon status = nci_core_init_rsp_packet_v2(ndev, skb);
132bcd684aaSBongsu Jeon
133bcd684aaSBongsu Jeon if (status != NCI_STATUS_OK)
134bcd684aaSBongsu Jeon goto exit;
135bcd684aaSBongsu Jeon
13620c239c1SJoe Perches pr_debug("nfcc_features 0x%x\n",
1376a2968aaSIlan Elias ndev->nfcc_features);
13820c239c1SJoe Perches pr_debug("num_supported_rf_interfaces %d\n",
1396a2968aaSIlan Elias ndev->num_supported_rf_interfaces);
14020c239c1SJoe Perches pr_debug("supported_rf_interfaces[0] 0x%x\n",
1416a2968aaSIlan Elias ndev->supported_rf_interfaces[0]);
14220c239c1SJoe Perches pr_debug("supported_rf_interfaces[1] 0x%x\n",
1436a2968aaSIlan Elias ndev->supported_rf_interfaces[1]);
14420c239c1SJoe Perches pr_debug("supported_rf_interfaces[2] 0x%x\n",
1456a2968aaSIlan Elias ndev->supported_rf_interfaces[2]);
14620c239c1SJoe Perches pr_debug("supported_rf_interfaces[3] 0x%x\n",
1476a2968aaSIlan Elias ndev->supported_rf_interfaces[3]);
14820c239c1SJoe Perches pr_debug("max_logical_connections %d\n",
1496a2968aaSIlan Elias ndev->max_logical_connections);
15020c239c1SJoe Perches pr_debug("max_routing_table_size %d\n",
1516a2968aaSIlan Elias ndev->max_routing_table_size);
15220c239c1SJoe Perches pr_debug("max_ctrl_pkt_payload_len %d\n",
153e8c0dacdSIlan Elias ndev->max_ctrl_pkt_payload_len);
15420c239c1SJoe Perches pr_debug("max_size_for_large_params %d\n",
155e8c0dacdSIlan Elias ndev->max_size_for_large_params);
15620c239c1SJoe Perches pr_debug("manufact_id 0x%x\n",
157e8c0dacdSIlan Elias ndev->manufact_id);
15820c239c1SJoe Perches pr_debug("manufact_specific_info 0x%x\n",
159e8c0dacdSIlan Elias ndev->manufact_specific_info);
1606a2968aaSIlan Elias
161e8c0dacdSIlan Elias exit:
162bcd684aaSBongsu Jeon nci_req_complete(ndev, status);
1636a2968aaSIlan Elias }
1646a2968aaSIlan Elias
nci_core_set_config_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)1657e035230SIlan Elias static void nci_core_set_config_rsp_packet(struct nci_dev *ndev,
166ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
1677e035230SIlan Elias {
168ddecf555SKrzysztof Kozlowski const struct nci_core_set_config_rsp *rsp = (void *)skb->data;
1697e035230SIlan Elias
1707e035230SIlan Elias pr_debug("status 0x%x\n", rsp->status);
1717e035230SIlan Elias
1727e035230SIlan Elias nci_req_complete(ndev, rsp->status);
1737e035230SIlan Elias }
1747e035230SIlan Elias
nci_rf_disc_map_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)1756a2968aaSIlan Elias static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev,
176ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
1776a2968aaSIlan Elias {
1786a2968aaSIlan Elias __u8 status = skb->data[0];
1796a2968aaSIlan Elias
18024bf3304SJoe Perches pr_debug("status 0x%x\n", status);
1816a2968aaSIlan Elias
1826a2968aaSIlan Elias nci_req_complete(ndev, status);
1836a2968aaSIlan Elias }
1846a2968aaSIlan Elias
nci_rf_disc_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)185ddecf555SKrzysztof Kozlowski static void nci_rf_disc_rsp_packet(struct nci_dev *ndev,
186ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
1876a2968aaSIlan Elias {
1884aeee687SChristophe Ricard struct nci_conn_info *conn_info;
1896a2968aaSIlan Elias __u8 status = skb->data[0];
1906a2968aaSIlan Elias
19124bf3304SJoe Perches pr_debug("status 0x%x\n", status);
1926a2968aaSIlan Elias
1934aeee687SChristophe Ricard if (status == NCI_STATUS_OK) {
1948939e47fSIlan Elias atomic_set(&ndev->state, NCI_DISCOVERY);
1956a2968aaSIlan Elias
19612bdf27dSChristophe Ricard conn_info = ndev->rf_conn_info;
1974aeee687SChristophe Ricard if (!conn_info) {
1984aeee687SChristophe Ricard conn_info = devm_kzalloc(&ndev->nfc_dev->dev,
1994aeee687SChristophe Ricard sizeof(struct nci_conn_info),
2004aeee687SChristophe Ricard GFP_KERNEL);
2014aeee687SChristophe Ricard if (!conn_info) {
2024aeee687SChristophe Ricard status = NCI_STATUS_REJECTED;
2034aeee687SChristophe Ricard goto exit;
2044aeee687SChristophe Ricard }
2054aeee687SChristophe Ricard conn_info->conn_id = NCI_STATIC_RF_CONN_ID;
2064aeee687SChristophe Ricard INIT_LIST_HEAD(&conn_info->list);
2074aeee687SChristophe Ricard list_add(&conn_info->list, &ndev->conn_info_list);
20812bdf27dSChristophe Ricard ndev->rf_conn_info = conn_info;
2094aeee687SChristophe Ricard }
2104aeee687SChristophe Ricard }
2114aeee687SChristophe Ricard
2124aeee687SChristophe Ricard exit:
2136a2968aaSIlan Elias nci_req_complete(ndev, status);
2146a2968aaSIlan Elias }
2156a2968aaSIlan Elias
nci_rf_disc_select_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)216019c4fbaSIlan Elias static void nci_rf_disc_select_rsp_packet(struct nci_dev *ndev,
217ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
218019c4fbaSIlan Elias {
219019c4fbaSIlan Elias __u8 status = skb->data[0];
220019c4fbaSIlan Elias
221019c4fbaSIlan Elias pr_debug("status 0x%x\n", status);
222019c4fbaSIlan Elias
223019c4fbaSIlan Elias /* Complete the request on intf_activated_ntf or generic_error_ntf */
224019c4fbaSIlan Elias if (status != NCI_STATUS_OK)
225019c4fbaSIlan Elias nci_req_complete(ndev, status);
226019c4fbaSIlan Elias }
227019c4fbaSIlan Elias
nci_rf_deactivate_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)2286a2968aaSIlan Elias static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev,
229ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
2306a2968aaSIlan Elias {
2316a2968aaSIlan Elias __u8 status = skb->data[0];
2326a2968aaSIlan Elias
23324bf3304SJoe Perches pr_debug("status 0x%x\n", status);
2346a2968aaSIlan Elias
235bd7e01bcSIlan Elias /* If target was active, complete the request only in deactivate_ntf */
236bd7e01bcSIlan Elias if ((status != NCI_STATUS_OK) ||
2378939e47fSIlan Elias (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
238019c4fbaSIlan Elias nci_clear_target_list(ndev);
2398939e47fSIlan Elias atomic_set(&ndev->state, NCI_IDLE);
2406a2968aaSIlan Elias nci_req_complete(ndev, status);
2416a2968aaSIlan Elias }
2428939e47fSIlan Elias }
2436a2968aaSIlan Elias
nci_nfcee_discover_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)244af9c8aa6SChristophe Ricard static void nci_nfcee_discover_rsp_packet(struct nci_dev *ndev,
245ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
246af9c8aa6SChristophe Ricard {
247ddecf555SKrzysztof Kozlowski const struct nci_nfcee_discover_rsp *discover_rsp;
248af9c8aa6SChristophe Ricard
249af9c8aa6SChristophe Ricard if (skb->len != 2) {
250af9c8aa6SChristophe Ricard nci_req_complete(ndev, NCI_STATUS_NFCEE_PROTOCOL_ERROR);
251af9c8aa6SChristophe Ricard return;
252af9c8aa6SChristophe Ricard }
253af9c8aa6SChristophe Ricard
254af9c8aa6SChristophe Ricard discover_rsp = (struct nci_nfcee_discover_rsp *)skb->data;
255af9c8aa6SChristophe Ricard
256af9c8aa6SChristophe Ricard if (discover_rsp->status != NCI_STATUS_OK ||
257af9c8aa6SChristophe Ricard discover_rsp->num_nfcee == 0)
258af9c8aa6SChristophe Ricard nci_req_complete(ndev, discover_rsp->status);
259af9c8aa6SChristophe Ricard }
260af9c8aa6SChristophe Ricard
nci_nfcee_mode_set_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)261f7f793f3SChristophe Ricard static void nci_nfcee_mode_set_rsp_packet(struct nci_dev *ndev,
262ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
263f7f793f3SChristophe Ricard {
264f7f793f3SChristophe Ricard __u8 status = skb->data[0];
265f7f793f3SChristophe Ricard
266f7f793f3SChristophe Ricard pr_debug("status 0x%x\n", status);
267f7f793f3SChristophe Ricard nci_req_complete(ndev, status);
268f7f793f3SChristophe Ricard }
269f7f793f3SChristophe Ricard
nci_core_conn_create_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)270736bb957SChristophe Ricard static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
271ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
272736bb957SChristophe Ricard {
273736bb957SChristophe Ricard __u8 status = skb->data[0];
2749b8d1a4cSChristophe Ricard struct nci_conn_info *conn_info = NULL;
275ddecf555SKrzysztof Kozlowski const struct nci_core_conn_create_rsp *rsp;
276736bb957SChristophe Ricard
277736bb957SChristophe Ricard pr_debug("status 0x%x\n", status);
278736bb957SChristophe Ricard
279736bb957SChristophe Ricard if (status == NCI_STATUS_OK) {
280736bb957SChristophe Ricard rsp = (struct nci_core_conn_create_rsp *)skb->data;
281736bb957SChristophe Ricard
28215d4a8daSChristophe Ricard conn_info = devm_kzalloc(&ndev->nfc_dev->dev,
28315d4a8daSChristophe Ricard sizeof(*conn_info), GFP_KERNEL);
28415d4a8daSChristophe Ricard if (!conn_info) {
285736bb957SChristophe Ricard status = NCI_STATUS_REJECTED;
286736bb957SChristophe Ricard goto exit;
287736bb957SChristophe Ricard }
288736bb957SChristophe Ricard
2899b8d1a4cSChristophe Ricard conn_info->dest_params = devm_kzalloc(&ndev->nfc_dev->dev,
2909b8d1a4cSChristophe Ricard sizeof(struct dest_spec_params),
2919b8d1a4cSChristophe Ricard GFP_KERNEL);
2929b8d1a4cSChristophe Ricard if (!conn_info->dest_params) {
2939b8d1a4cSChristophe Ricard status = NCI_STATUS_REJECTED;
2949b8d1a4cSChristophe Ricard goto free_conn_info;
2959b8d1a4cSChristophe Ricard }
2969b8d1a4cSChristophe Ricard
2979b8d1a4cSChristophe Ricard conn_info->dest_type = ndev->cur_dest_type;
2989b8d1a4cSChristophe Ricard conn_info->dest_params->id = ndev->cur_params.id;
2999b8d1a4cSChristophe Ricard conn_info->dest_params->protocol = ndev->cur_params.protocol;
30015d4a8daSChristophe Ricard conn_info->conn_id = rsp->conn_id;
30115d4a8daSChristophe Ricard
30215d4a8daSChristophe Ricard /* Note: data_exchange_cb and data_exchange_cb_context need to
30315d4a8daSChristophe Ricard * be specify out of nci_core_conn_create_rsp_packet
30415d4a8daSChristophe Ricard */
30515d4a8daSChristophe Ricard
30615d4a8daSChristophe Ricard INIT_LIST_HEAD(&conn_info->list);
30715d4a8daSChristophe Ricard list_add(&conn_info->list, &ndev->conn_info_list);
30815d4a8daSChristophe Ricard
3099b8d1a4cSChristophe Ricard if (ndev->cur_params.id == ndev->hci_dev->nfcee_id)
31015d4a8daSChristophe Ricard ndev->hci_dev->conn_info = conn_info;
31115d4a8daSChristophe Ricard
312736bb957SChristophe Ricard conn_info->conn_id = rsp->conn_id;
313736bb957SChristophe Ricard conn_info->max_pkt_payload_len = rsp->max_ctrl_pkt_payload_len;
3143ba5c846SChristophe Ricard atomic_set(&conn_info->credits_cnt, rsp->credits_cnt);
315736bb957SChristophe Ricard }
316736bb957SChristophe Ricard
3179b8d1a4cSChristophe Ricard free_conn_info:
3189b8d1a4cSChristophe Ricard if (status == NCI_STATUS_REJECTED)
3199b8d1a4cSChristophe Ricard devm_kfree(&ndev->nfc_dev->dev, conn_info);
320736bb957SChristophe Ricard exit:
3219b8d1a4cSChristophe Ricard
322736bb957SChristophe Ricard nci_req_complete(ndev, status);
323736bb957SChristophe Ricard }
324736bb957SChristophe Ricard
nci_core_conn_close_rsp_packet(struct nci_dev * ndev,const struct sk_buff * skb)325736bb957SChristophe Ricard static void nci_core_conn_close_rsp_packet(struct nci_dev *ndev,
326ddecf555SKrzysztof Kozlowski const struct sk_buff *skb)
327736bb957SChristophe Ricard {
32815d4a8daSChristophe Ricard struct nci_conn_info *conn_info;
329736bb957SChristophe Ricard __u8 status = skb->data[0];
330736bb957SChristophe Ricard
331736bb957SChristophe Ricard pr_debug("status 0x%x\n", status);
33215d4a8daSChristophe Ricard if (status == NCI_STATUS_OK) {
333de5ea851SChristophe Ricard conn_info = nci_get_conn_info_by_conn_id(ndev,
334de5ea851SChristophe Ricard ndev->cur_conn_id);
33515d4a8daSChristophe Ricard if (conn_info) {
33615d4a8daSChristophe Ricard list_del(&conn_info->list);
337*1b1499a8SLin Ma if (conn_info == ndev->rf_conn_info)
338*1b1499a8SLin Ma ndev->rf_conn_info = NULL;
33915d4a8daSChristophe Ricard devm_kfree(&ndev->nfc_dev->dev, conn_info);
34015d4a8daSChristophe Ricard }
34115d4a8daSChristophe Ricard }
342736bb957SChristophe Ricard nci_req_complete(ndev, status);
343736bb957SChristophe Ricard }
344736bb957SChristophe Ricard
nci_rsp_packet(struct nci_dev * ndev,struct sk_buff * skb)3456a2968aaSIlan Elias void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
3466a2968aaSIlan Elias {
3476a2968aaSIlan Elias __u16 rsp_opcode = nci_opcode(skb->data);
3486a2968aaSIlan Elias
3496a2968aaSIlan Elias /* we got a rsp, stop the cmd timer */
3506a2968aaSIlan Elias del_timer(&ndev->cmd_timer);
3516a2968aaSIlan Elias
35220c239c1SJoe Perches pr_debug("NCI RX: MT=rsp, PBF=%d, GID=0x%x, OID=0x%x, plen=%d\n",
3536a2968aaSIlan Elias nci_pbf(skb->data),
3546a2968aaSIlan Elias nci_opcode_gid(rsp_opcode),
3556a2968aaSIlan Elias nci_opcode_oid(rsp_opcode),
3566a2968aaSIlan Elias nci_plen(skb->data));
3576a2968aaSIlan Elias
3586a2968aaSIlan Elias /* strip the nci control header */
3596a2968aaSIlan Elias skb_pull(skb, NCI_CTRL_HDR_SIZE);
3606a2968aaSIlan Elias
361b6355e97SSamuel Ortiz if (nci_opcode_gid(rsp_opcode) == NCI_GID_PROPRIETARY) {
362b6355e97SSamuel Ortiz if (nci_prop_rsp_packet(ndev, rsp_opcode, skb) == -ENOTSUPP) {
363b6355e97SSamuel Ortiz pr_err("unsupported rsp opcode 0x%x\n",
364b6355e97SSamuel Ortiz rsp_opcode);
365b6355e97SSamuel Ortiz }
366b6355e97SSamuel Ortiz
367b6355e97SSamuel Ortiz goto end;
368b6355e97SSamuel Ortiz }
369b6355e97SSamuel Ortiz
3706a2968aaSIlan Elias switch (rsp_opcode) {
3716a2968aaSIlan Elias case NCI_OP_CORE_RESET_RSP:
3726a2968aaSIlan Elias nci_core_reset_rsp_packet(ndev, skb);
3736a2968aaSIlan Elias break;
3746a2968aaSIlan Elias
3756a2968aaSIlan Elias case NCI_OP_CORE_INIT_RSP:
3766a2968aaSIlan Elias nci_core_init_rsp_packet(ndev, skb);
3776a2968aaSIlan Elias break;
3786a2968aaSIlan Elias
3797e035230SIlan Elias case NCI_OP_CORE_SET_CONFIG_RSP:
3807e035230SIlan Elias nci_core_set_config_rsp_packet(ndev, skb);
3817e035230SIlan Elias break;
3827e035230SIlan Elias
383736bb957SChristophe Ricard case NCI_OP_CORE_CONN_CREATE_RSP:
384736bb957SChristophe Ricard nci_core_conn_create_rsp_packet(ndev, skb);
385736bb957SChristophe Ricard break;
386736bb957SChristophe Ricard
387736bb957SChristophe Ricard case NCI_OP_CORE_CONN_CLOSE_RSP:
388736bb957SChristophe Ricard nci_core_conn_close_rsp_packet(ndev, skb);
389736bb957SChristophe Ricard break;
390736bb957SChristophe Ricard
3916a2968aaSIlan Elias case NCI_OP_RF_DISCOVER_MAP_RSP:
3926a2968aaSIlan Elias nci_rf_disc_map_rsp_packet(ndev, skb);
3936a2968aaSIlan Elias break;
3946a2968aaSIlan Elias
3956a2968aaSIlan Elias case NCI_OP_RF_DISCOVER_RSP:
3966a2968aaSIlan Elias nci_rf_disc_rsp_packet(ndev, skb);
3976a2968aaSIlan Elias break;
3986a2968aaSIlan Elias
399019c4fbaSIlan Elias case NCI_OP_RF_DISCOVER_SELECT_RSP:
400019c4fbaSIlan Elias nci_rf_disc_select_rsp_packet(ndev, skb);
401019c4fbaSIlan Elias break;
402019c4fbaSIlan Elias
4036a2968aaSIlan Elias case NCI_OP_RF_DEACTIVATE_RSP:
4046a2968aaSIlan Elias nci_rf_deactivate_rsp_packet(ndev, skb);
4056a2968aaSIlan Elias break;
4066a2968aaSIlan Elias
407af9c8aa6SChristophe Ricard case NCI_OP_NFCEE_DISCOVER_RSP:
408af9c8aa6SChristophe Ricard nci_nfcee_discover_rsp_packet(ndev, skb);
409af9c8aa6SChristophe Ricard break;
410af9c8aa6SChristophe Ricard
411f7f793f3SChristophe Ricard case NCI_OP_NFCEE_MODE_SET_RSP:
412f7f793f3SChristophe Ricard nci_nfcee_mode_set_rsp_packet(ndev, skb);
413f7f793f3SChristophe Ricard break;
414f7f793f3SChristophe Ricard
4156a2968aaSIlan Elias default:
416ed1e0ad8SJoe Perches pr_err("unknown rsp opcode 0x%x\n", rsp_opcode);
4176a2968aaSIlan Elias break;
4186a2968aaSIlan Elias }
4196a2968aaSIlan Elias
4200a97a3cbSRobert Dolca nci_core_rsp_packet(ndev, rsp_opcode, skb);
421b6355e97SSamuel Ortiz end:
4226a2968aaSIlan Elias kfree_skb(skb);
4236a2968aaSIlan Elias
4246a2968aaSIlan Elias /* trigger the next cmd */
4256a2968aaSIlan Elias atomic_set(&ndev->cmd_cnt, 1);
4266a2968aaSIlan Elias if (!skb_queue_empty(&ndev->cmd_q))
4276a2968aaSIlan Elias queue_work(ndev->cmd_wq, &ndev->cmd_work);
4286a2968aaSIlan Elias }
429