blob: 64fc58a6e28bbc1dafc12bf3c98db4e6a1487fc9 [file] [log] [blame]
Ilan Elias6a2968a2011-09-18 11:19:35 +03001/*
2 * The NFC Controller Interface is the communication protocol between an
3 * NFC Controller (NFCC) and a Device Host (DH).
4 *
5 * Copyright (C) 2011 Texas Instruments, Inc.
6 *
7 * Written by Ilan Elias <ilane@ti.com>
8 *
9 * Acknowledgements:
10 * This file is based on hci_event.c, which was written
11 * by Maxim Krasnyansky.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2
15 * as published by the Free Software Foundation
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 */
27
28#include <linux/types.h>
29#include <linux/interrupt.h>
30#include <linux/bitops.h>
31#include <linux/skbuff.h>
32
33#include "../nfc.h"
34#include <net/nfc/nci.h>
35#include <net/nfc/nci_core.h>
36
37/* Handle NCI Response packets */
38
39static void nci_core_reset_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
40{
41 struct nci_core_reset_rsp *rsp = (void *) skb->data;
42
43 nfc_dbg("entry, status 0x%x", rsp->status);
44
Ilan Eliase8c0dac2011-11-09 12:09:14 +020045 if (rsp->status == NCI_STATUS_OK) {
Ilan Elias6a2968a2011-09-18 11:19:35 +030046 ndev->nci_ver = rsp->nci_ver;
Ilan Eliase8c0dac2011-11-09 12:09:14 +020047 nfc_dbg("nci_ver 0x%x, config_status 0x%x",
48 rsp->nci_ver, rsp->config_status);
49 }
Ilan Elias6a2968a2011-09-18 11:19:35 +030050
51 nci_req_complete(ndev, rsp->status);
52}
53
54static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
55{
56 struct nci_core_init_rsp_1 *rsp_1 = (void *) skb->data;
57 struct nci_core_init_rsp_2 *rsp_2;
58
59 nfc_dbg("entry, status 0x%x", rsp_1->status);
60
61 if (rsp_1->status != NCI_STATUS_OK)
Ilan Eliase8c0dac2011-11-09 12:09:14 +020062 goto exit;
Ilan Elias6a2968a2011-09-18 11:19:35 +030063
64 ndev->nfcc_features = __le32_to_cpu(rsp_1->nfcc_features);
65 ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces;
66
67 if (ndev->num_supported_rf_interfaces >
Ilan Eliase8c0dac2011-11-09 12:09:14 +020068 NCI_MAX_SUPPORTED_RF_INTERFACES) {
Ilan Elias6a2968a2011-09-18 11:19:35 +030069 ndev->num_supported_rf_interfaces =
70 NCI_MAX_SUPPORTED_RF_INTERFACES;
71 }
72
73 memcpy(ndev->supported_rf_interfaces,
74 rsp_1->supported_rf_interfaces,
75 ndev->num_supported_rf_interfaces);
76
Ilan Eliase8c0dac2011-11-09 12:09:14 +020077 rsp_2 = (void *) (skb->data + 6 + rsp_1->num_supported_rf_interfaces);
Ilan Elias6a2968a2011-09-18 11:19:35 +030078
79 ndev->max_logical_connections =
80 rsp_2->max_logical_connections;
81 ndev->max_routing_table_size =
82 __le16_to_cpu(rsp_2->max_routing_table_size);
Ilan Eliase8c0dac2011-11-09 12:09:14 +020083 ndev->max_ctrl_pkt_payload_len =
84 rsp_2->max_ctrl_pkt_payload_len;
85 ndev->max_size_for_large_params =
86 __le16_to_cpu(rsp_2->max_size_for_large_params);
87 ndev->max_data_pkt_payload_size =
88 rsp_2->max_data_pkt_payload_size;
89 ndev->initial_num_credits =
90 rsp_2->initial_num_credits;
91 ndev->manufact_id =
92 rsp_2->manufact_id;
93 ndev->manufact_specific_info =
94 __le32_to_cpu(rsp_2->manufact_specific_info);
95
96 atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
Ilan Elias6a2968a2011-09-18 11:19:35 +030097
98 nfc_dbg("nfcc_features 0x%x",
99 ndev->nfcc_features);
100 nfc_dbg("num_supported_rf_interfaces %d",
101 ndev->num_supported_rf_interfaces);
102 nfc_dbg("supported_rf_interfaces[0] 0x%x",
103 ndev->supported_rf_interfaces[0]);
104 nfc_dbg("supported_rf_interfaces[1] 0x%x",
105 ndev->supported_rf_interfaces[1]);
106 nfc_dbg("supported_rf_interfaces[2] 0x%x",
107 ndev->supported_rf_interfaces[2]);
108 nfc_dbg("supported_rf_interfaces[3] 0x%x",
109 ndev->supported_rf_interfaces[3]);
110 nfc_dbg("max_logical_connections %d",
111 ndev->max_logical_connections);
112 nfc_dbg("max_routing_table_size %d",
113 ndev->max_routing_table_size);
Ilan Eliase8c0dac2011-11-09 12:09:14 +0200114 nfc_dbg("max_ctrl_pkt_payload_len %d",
115 ndev->max_ctrl_pkt_payload_len);
116 nfc_dbg("max_size_for_large_params %d",
117 ndev->max_size_for_large_params);
118 nfc_dbg("max_data_pkt_payload_size %d",
119 ndev->max_data_pkt_payload_size);
120 nfc_dbg("initial_num_credits %d",
121 ndev->initial_num_credits);
122 nfc_dbg("manufact_id 0x%x",
123 ndev->manufact_id);
124 nfc_dbg("manufact_specific_info 0x%x",
125 ndev->manufact_specific_info);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300126
Ilan Eliase8c0dac2011-11-09 12:09:14 +0200127exit:
Ilan Elias6a2968a2011-09-18 11:19:35 +0300128 nci_req_complete(ndev, rsp_1->status);
129}
130
131static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
132 struct sk_buff *skb)
133{
134 struct nci_core_conn_create_rsp *rsp = (void *) skb->data;
135
136 nfc_dbg("entry, status 0x%x", rsp->status);
137
138 if (rsp->status != NCI_STATUS_OK)
139 return;
140
141 ndev->max_pkt_payload_size = rsp->max_pkt_payload_size;
142 ndev->initial_num_credits = rsp->initial_num_credits;
143 ndev->conn_id = rsp->conn_id;
144
145 atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
146
147 nfc_dbg("max_pkt_payload_size %d", ndev->max_pkt_payload_size);
148 nfc_dbg("initial_num_credits %d", ndev->initial_num_credits);
149 nfc_dbg("conn_id %d", ndev->conn_id);
150}
151
152static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev,
153 struct sk_buff *skb)
154{
155 __u8 status = skb->data[0];
156
157 nfc_dbg("entry, status 0x%x", status);
158
159 nci_req_complete(ndev, status);
160}
161
162static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
163{
164 __u8 status = skb->data[0];
165
166 nfc_dbg("entry, status 0x%x", status);
167
168 if (status == NCI_STATUS_OK)
169 set_bit(NCI_DISCOVERY, &ndev->flags);
170
171 nci_req_complete(ndev, status);
172}
173
174static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev,
175 struct sk_buff *skb)
176{
177 __u8 status = skb->data[0];
178
179 nfc_dbg("entry, status 0x%x", status);
180
181 clear_bit(NCI_DISCOVERY, &ndev->flags);
182
183 nci_req_complete(ndev, status);
184}
185
186void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
187{
188 __u16 rsp_opcode = nci_opcode(skb->data);
189
190 /* we got a rsp, stop the cmd timer */
191 del_timer(&ndev->cmd_timer);
192
193 nfc_dbg("NCI RX: MT=rsp, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
194 nci_pbf(skb->data),
195 nci_opcode_gid(rsp_opcode),
196 nci_opcode_oid(rsp_opcode),
197 nci_plen(skb->data));
198
199 /* strip the nci control header */
200 skb_pull(skb, NCI_CTRL_HDR_SIZE);
201
202 switch (rsp_opcode) {
203 case NCI_OP_CORE_RESET_RSP:
204 nci_core_reset_rsp_packet(ndev, skb);
205 break;
206
207 case NCI_OP_CORE_INIT_RSP:
208 nci_core_init_rsp_packet(ndev, skb);
209 break;
210
211 case NCI_OP_CORE_CONN_CREATE_RSP:
212 nci_core_conn_create_rsp_packet(ndev, skb);
213 break;
214
215 case NCI_OP_RF_DISCOVER_MAP_RSP:
216 nci_rf_disc_map_rsp_packet(ndev, skb);
217 break;
218
219 case NCI_OP_RF_DISCOVER_RSP:
220 nci_rf_disc_rsp_packet(ndev, skb);
221 break;
222
223 case NCI_OP_RF_DEACTIVATE_RSP:
224 nci_rf_deactivate_rsp_packet(ndev, skb);
225 break;
226
227 default:
228 nfc_err("unknown rsp opcode 0x%x", rsp_opcode);
229 break;
230 }
231
232 kfree_skb(skb);
233
234 /* trigger the next cmd */
235 atomic_set(&ndev->cmd_cnt, 1);
236 if (!skb_queue_empty(&ndev->cmd_q))
237 queue_work(ndev->cmd_wq, &ndev->cmd_work);
238}