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 28*ddecf555SKrzysztof Kozlowski static void nci_core_reset_rsp_packet(struct nci_dev *ndev, 29*ddecf555SKrzysztof Kozlowski const struct sk_buff *skb) 306a2968aaSIlan Elias { 31*ddecf555SKrzysztof 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 47*ddecf555SKrzysztof Kozlowski static u8 nci_core_init_rsp_packet_v1(struct nci_dev *ndev, 48*ddecf555SKrzysztof Kozlowski const struct sk_buff *skb) 496a2968aaSIlan Elias { 50*ddecf555SKrzysztof Kozlowski const struct nci_core_init_rsp_1 *rsp_1 = (void *)skb->data; 51*ddecf555SKrzysztof 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 86*ddecf555SKrzysztof Kozlowski static u8 nci_core_init_rsp_packet_v2(struct nci_dev *ndev, 87*ddecf555SKrzysztof Kozlowski const struct sk_buff *skb) 88bcd684aaSBongsu Jeon { 89*ddecf555SKrzysztof Kozlowski const struct nci_core_init_rsp_nci_ver2 *rsp = (void *)skb->data; 90*ddecf555SKrzysztof 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 124*ddecf555SKrzysztof 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 1657e035230SIlan Elias static void nci_core_set_config_rsp_packet(struct nci_dev *ndev, 166*ddecf555SKrzysztof Kozlowski const struct sk_buff *skb) 1677e035230SIlan Elias { 168*ddecf555SKrzysztof 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 1756a2968aaSIlan Elias static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev, 176*ddecf555SKrzysztof 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 185*ddecf555SKrzysztof Kozlowski static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, 186*ddecf555SKrzysztof 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 216019c4fbaSIlan Elias static void nci_rf_disc_select_rsp_packet(struct nci_dev *ndev, 217*ddecf555SKrzysztof 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 2286a2968aaSIlan Elias static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev, 229*ddecf555SKrzysztof 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 244af9c8aa6SChristophe Ricard static void nci_nfcee_discover_rsp_packet(struct nci_dev *ndev, 245*ddecf555SKrzysztof Kozlowski const struct sk_buff *skb) 246af9c8aa6SChristophe Ricard { 247*ddecf555SKrzysztof 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 261f7f793f3SChristophe Ricard static void nci_nfcee_mode_set_rsp_packet(struct nci_dev *ndev, 262*ddecf555SKrzysztof 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 270736bb957SChristophe Ricard static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev, 271*ddecf555SKrzysztof Kozlowski const struct sk_buff *skb) 272736bb957SChristophe Ricard { 273736bb957SChristophe Ricard __u8 status = skb->data[0]; 2749b8d1a4cSChristophe Ricard struct nci_conn_info *conn_info = NULL; 275*ddecf555SKrzysztof 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 325736bb957SChristophe Ricard static void nci_core_conn_close_rsp_packet(struct nci_dev *ndev, 326*ddecf555SKrzysztof 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); 33715d4a8daSChristophe Ricard devm_kfree(&ndev->nfc_dev->dev, conn_info); 33815d4a8daSChristophe Ricard } 33915d4a8daSChristophe Ricard } 340736bb957SChristophe Ricard nci_req_complete(ndev, status); 341736bb957SChristophe Ricard } 342736bb957SChristophe Ricard 3436a2968aaSIlan Elias void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb) 3446a2968aaSIlan Elias { 3456a2968aaSIlan Elias __u16 rsp_opcode = nci_opcode(skb->data); 3466a2968aaSIlan Elias 3476a2968aaSIlan Elias /* we got a rsp, stop the cmd timer */ 3486a2968aaSIlan Elias del_timer(&ndev->cmd_timer); 3496a2968aaSIlan Elias 35020c239c1SJoe Perches pr_debug("NCI RX: MT=rsp, PBF=%d, GID=0x%x, OID=0x%x, plen=%d\n", 3516a2968aaSIlan Elias nci_pbf(skb->data), 3526a2968aaSIlan Elias nci_opcode_gid(rsp_opcode), 3536a2968aaSIlan Elias nci_opcode_oid(rsp_opcode), 3546a2968aaSIlan Elias nci_plen(skb->data)); 3556a2968aaSIlan Elias 3566a2968aaSIlan Elias /* strip the nci control header */ 3576a2968aaSIlan Elias skb_pull(skb, NCI_CTRL_HDR_SIZE); 3586a2968aaSIlan Elias 359b6355e97SSamuel Ortiz if (nci_opcode_gid(rsp_opcode) == NCI_GID_PROPRIETARY) { 360b6355e97SSamuel Ortiz if (nci_prop_rsp_packet(ndev, rsp_opcode, skb) == -ENOTSUPP) { 361b6355e97SSamuel Ortiz pr_err("unsupported rsp opcode 0x%x\n", 362b6355e97SSamuel Ortiz rsp_opcode); 363b6355e97SSamuel Ortiz } 364b6355e97SSamuel Ortiz 365b6355e97SSamuel Ortiz goto end; 366b6355e97SSamuel Ortiz } 367b6355e97SSamuel Ortiz 3686a2968aaSIlan Elias switch (rsp_opcode) { 3696a2968aaSIlan Elias case NCI_OP_CORE_RESET_RSP: 3706a2968aaSIlan Elias nci_core_reset_rsp_packet(ndev, skb); 3716a2968aaSIlan Elias break; 3726a2968aaSIlan Elias 3736a2968aaSIlan Elias case NCI_OP_CORE_INIT_RSP: 3746a2968aaSIlan Elias nci_core_init_rsp_packet(ndev, skb); 3756a2968aaSIlan Elias break; 3766a2968aaSIlan Elias 3777e035230SIlan Elias case NCI_OP_CORE_SET_CONFIG_RSP: 3787e035230SIlan Elias nci_core_set_config_rsp_packet(ndev, skb); 3797e035230SIlan Elias break; 3807e035230SIlan Elias 381736bb957SChristophe Ricard case NCI_OP_CORE_CONN_CREATE_RSP: 382736bb957SChristophe Ricard nci_core_conn_create_rsp_packet(ndev, skb); 383736bb957SChristophe Ricard break; 384736bb957SChristophe Ricard 385736bb957SChristophe Ricard case NCI_OP_CORE_CONN_CLOSE_RSP: 386736bb957SChristophe Ricard nci_core_conn_close_rsp_packet(ndev, skb); 387736bb957SChristophe Ricard break; 388736bb957SChristophe Ricard 3896a2968aaSIlan Elias case NCI_OP_RF_DISCOVER_MAP_RSP: 3906a2968aaSIlan Elias nci_rf_disc_map_rsp_packet(ndev, skb); 3916a2968aaSIlan Elias break; 3926a2968aaSIlan Elias 3936a2968aaSIlan Elias case NCI_OP_RF_DISCOVER_RSP: 3946a2968aaSIlan Elias nci_rf_disc_rsp_packet(ndev, skb); 3956a2968aaSIlan Elias break; 3966a2968aaSIlan Elias 397019c4fbaSIlan Elias case NCI_OP_RF_DISCOVER_SELECT_RSP: 398019c4fbaSIlan Elias nci_rf_disc_select_rsp_packet(ndev, skb); 399019c4fbaSIlan Elias break; 400019c4fbaSIlan Elias 4016a2968aaSIlan Elias case NCI_OP_RF_DEACTIVATE_RSP: 4026a2968aaSIlan Elias nci_rf_deactivate_rsp_packet(ndev, skb); 4036a2968aaSIlan Elias break; 4046a2968aaSIlan Elias 405af9c8aa6SChristophe Ricard case NCI_OP_NFCEE_DISCOVER_RSP: 406af9c8aa6SChristophe Ricard nci_nfcee_discover_rsp_packet(ndev, skb); 407af9c8aa6SChristophe Ricard break; 408af9c8aa6SChristophe Ricard 409f7f793f3SChristophe Ricard case NCI_OP_NFCEE_MODE_SET_RSP: 410f7f793f3SChristophe Ricard nci_nfcee_mode_set_rsp_packet(ndev, skb); 411f7f793f3SChristophe Ricard break; 412f7f793f3SChristophe Ricard 4136a2968aaSIlan Elias default: 414ed1e0ad8SJoe Perches pr_err("unknown rsp opcode 0x%x\n", rsp_opcode); 4156a2968aaSIlan Elias break; 4166a2968aaSIlan Elias } 4176a2968aaSIlan Elias 4180a97a3cbSRobert Dolca nci_core_rsp_packet(ndev, rsp_opcode, skb); 419b6355e97SSamuel Ortiz end: 4206a2968aaSIlan Elias kfree_skb(skb); 4216a2968aaSIlan Elias 4226a2968aaSIlan Elias /* trigger the next cmd */ 4236a2968aaSIlan Elias atomic_set(&ndev->cmd_cnt, 1); 4246a2968aaSIlan Elias if (!skb_queue_empty(&ndev->cmd_q)) 4256a2968aaSIlan Elias queue_work(ndev->cmd_wq, &ndev->cmd_work); 4266a2968aaSIlan Elias } 427