ntf.c 7.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
/*
 *  The NFC Controller Interface is the communication protocol between an
 *  NFC Controller (NFCC) and a Device Host (DH).
 *
 *  Copyright (C) 2011 Texas Instruments, Inc.
 *
 *  Written by Ilan Elias <ilane@ti.com>
 *
 *  Acknowledgements:
 *  This file is based on hci_event.c, which was written
 *  by Maxim Krasnyansky.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/skbuff.h>

#include "../nfc.h"
#include <net/nfc/nci.h>
#include <net/nfc/nci_core.h>
#include <linux/nfc.h>

/* Handle NCI Notification packets */

static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
						struct sk_buff *skb)
{
	struct nci_core_conn_credit_ntf *ntf = (void *) skb->data;
	int i;

	nfc_dbg("entry, num_entries %d", ntf->num_entries);

	if (ntf->num_entries > NCI_MAX_NUM_CONN)
		ntf->num_entries = NCI_MAX_NUM_CONN;

	/* update the credits */
	for (i = 0; i < ntf->num_entries; i++) {
		nfc_dbg("entry[%d]: conn_id %d, credits %d", i,
			ntf->conn_entries[i].conn_id,
			ntf->conn_entries[i].credits);

57
		if (ntf->conn_entries[i].conn_id == NCI_STATIC_RF_CONN_ID) {
58 59 60 61 62 63 64 65 66 67 68
			/* found static rf connection */
			atomic_add(ntf->conn_entries[i].credits,
				&ndev->credits_cnt);
		}
	}

	/* trigger the next tx */
	if (!skb_queue_empty(&ndev->tx_q))
		queue_work(ndev->tx_wq, &ndev->tx_work);
}

69 70
static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
			struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
{
	struct rf_tech_specific_params_nfca_poll *nfca_poll;

	nfca_poll = &ntf->rf_tech_specific_params.nfca_poll;

	nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
	data += 2;

	nfca_poll->nfcid1_len = *data++;

	nfc_dbg("sens_res 0x%x, nfcid1_len %d",
		nfca_poll->sens_res,
		nfca_poll->nfcid1_len);

	memcpy(nfca_poll->nfcid1, data, nfca_poll->nfcid1_len);
	data += nfca_poll->nfcid1_len;

	nfca_poll->sel_res_len = *data++;

	if (nfca_poll->sel_res_len != 0)
		nfca_poll->sel_res = *data++;

93
	nfc_dbg("sel_res_len %d, sel_res 0x%x",
94
		nfca_poll->sel_res_len,
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
		nfca_poll->sel_res);

	return data;
}

static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
			struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
{
	struct activation_params_nfca_poll_iso_dep *nfca_poll;

	switch (ntf->activation_rf_tech_and_mode) {
	case NCI_NFC_A_PASSIVE_POLL_MODE:
		nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
		nfca_poll->rats_res_len = *data++;
		if (nfca_poll->rats_res_len > 0) {
			memcpy(nfca_poll->rats_res,
111
				data,
112
				nfca_poll->rats_res_len);
113 114 115 116
		}
		break;

	default:
117 118
		nfc_err("unsupported activation_rf_tech_and_mode 0x%x",
			ntf->activation_rf_tech_and_mode);
119 120 121 122 123 124 125
		return -EPROTO;
	}

	return 0;
}

static void nci_target_found(struct nci_dev *ndev,
126
				struct nci_rf_intf_activated_ntf *ntf)
127 128 129 130 131 132 133
{
	struct nfc_target nfc_tgt;

	if (ntf->rf_protocol == NCI_RF_PROTOCOL_T2T)	/* T2T MifareUL */
		nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK;
	else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP)	/* 4A */
		nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK;
134 135
	else
		nfc_tgt.supported_protocols = 0;
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

	nfc_tgt.sens_res = ntf->rf_tech_specific_params.nfca_poll.sens_res;
	nfc_tgt.sel_res = ntf->rf_tech_specific_params.nfca_poll.sel_res;

	if (!(nfc_tgt.supported_protocols & ndev->poll_prots)) {
		nfc_dbg("the target found does not have the desired protocol");
		return;
	}

	nfc_dbg("new target found,  supported_protocols 0x%x",
		nfc_tgt.supported_protocols);

	ndev->target_available_prots = nfc_tgt.supported_protocols;

	nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1);
}

153 154
static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
						struct sk_buff *skb)
155
{
156
	struct nci_rf_intf_activated_ntf ntf;
157
	__u8 *data = skb->data;
158
	int err = 0;
159 160 161 162

	clear_bit(NCI_DISCOVERY, &ndev->flags);
	set_bit(NCI_POLL_ACTIVE, &ndev->flags);

163 164
	ntf.rf_discovery_id = *data++;
	ntf.rf_interface_type = *data++;
165
	ntf.rf_protocol = *data++;
166
	ntf.activation_rf_tech_and_mode = *data++;
167 168
	ntf.rf_tech_specific_params_len = *data++;

169 170 171 172 173 174
	nfc_dbg("rf_discovery_id %d", ntf.rf_discovery_id);
	nfc_dbg("rf_interface_type 0x%x", ntf.rf_interface_type);
	nfc_dbg("rf_protocol 0x%x", ntf.rf_protocol);
	nfc_dbg("activation_rf_tech_and_mode 0x%x",
		ntf.activation_rf_tech_and_mode);
	nfc_dbg("rf_tech_specific_params_len %d",
175 176
		ntf.rf_tech_specific_params_len);

177 178 179 180 181 182 183 184 185 186 187 188 189
	if (ntf.rf_tech_specific_params_len > 0) {
		switch (ntf.activation_rf_tech_and_mode) {
		case NCI_NFC_A_PASSIVE_POLL_MODE:
			data = nci_extract_rf_params_nfca_passive_poll(ndev,
				&ntf, data);
			break;

		default:
			nfc_err("unsupported activation_rf_tech_and_mode 0x%x",
				ntf.activation_rf_tech_and_mode);
			return;
		}
	}
190

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
	ntf.data_exch_rf_tech_and_mode = *data++;
	ntf.data_exch_tx_bit_rate = *data++;
	ntf.data_exch_rx_bit_rate = *data++;
	ntf.activation_params_len = *data++;

	nfc_dbg("data_exch_rf_tech_and_mode 0x%x",
		ntf.data_exch_rf_tech_and_mode);
	nfc_dbg("data_exch_tx_bit_rate 0x%x",
		ntf.data_exch_tx_bit_rate);
	nfc_dbg("data_exch_rx_bit_rate 0x%x",
		ntf.data_exch_rx_bit_rate);
	nfc_dbg("activation_params_len %d",
		ntf.activation_params_len);

	if (ntf.activation_params_len > 0) {
		switch (ntf.rf_interface_type) {
		case NCI_RF_INTERFACE_ISO_DEP:
			err = nci_extract_activation_params_iso_dep(ndev,
				&ntf, data);
			break;

		case NCI_RF_INTERFACE_FRAME:
			/* no activation params */
			break;

		default:
			nfc_err("unsupported rf_interface_type 0x%x",
				ntf.rf_interface_type);
			return;
		}
221 222
	}

223
	if (!err)
224 225 226 227 228 229
		nci_target_found(ndev, &ntf);
}

static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
					struct sk_buff *skb)
{
230
	struct nci_rf_deactivate_ntf *ntf = (void *) skb->data;
231

232
	nfc_dbg("entry, type 0x%x, reason 0x%x", ntf->type, ntf->reason);
233 234 235 236 237 238 239 240 241 242 243 244 245

	clear_bit(NCI_POLL_ACTIVE, &ndev->flags);
	ndev->target_active_prot = 0;

	/* drop tx data queue */
	skb_queue_purge(&ndev->tx_q);

	/* drop partial rx data packet */
	if (ndev->rx_data_reassembly) {
		kfree_skb(ndev->rx_data_reassembly);
		ndev->rx_data_reassembly = 0;
	}

246 247 248
	/* set the available credits to initial value */
	atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);

249
	/* complete the data exchange transaction, if exists */
250
	if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
		nci_data_exchange_complete(ndev, NULL, -EIO);
}

void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
{
	__u16 ntf_opcode = nci_opcode(skb->data);

	nfc_dbg("NCI RX: MT=ntf, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
			nci_pbf(skb->data),
			nci_opcode_gid(ntf_opcode),
			nci_opcode_oid(ntf_opcode),
			nci_plen(skb->data));

	/* strip the nci control header */
	skb_pull(skb, NCI_CTRL_HDR_SIZE);

	switch (ntf_opcode) {
	case NCI_OP_CORE_CONN_CREDITS_NTF:
		nci_core_conn_credits_ntf_packet(ndev, skb);
		break;

272 273
	case NCI_OP_RF_INTF_ACTIVATED_NTF:
		nci_rf_intf_activated_ntf_packet(ndev, skb);
274 275 276 277 278 279 280 281 282 283 284 285 286
		break;

	case NCI_OP_RF_DEACTIVATE_NTF:
		nci_rf_deactivate_ntf_packet(ndev, skb);
		break;

	default:
		nfc_err("unknown ntf opcode 0x%x", ntf_opcode);
		break;
	}

	kfree_skb(skb);
}