2011-09-18 11:19:35 +03:00
/*
* The NFC Controller Interface is the communication protocol between an
* NFC Controller ( NFCC ) and a Device Host ( DH ) .
*
2014-07-22 19:48:38 +02:00
* Copyright ( C ) 2014 Marvell International Ltd .
2011-09-18 11:19:35 +03:00
* 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
2013-12-06 08:56:16 -08:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2011-09-18 11:19:35 +03:00
*
*/
2011-12-14 16:43:05 +01:00
# define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
2011-11-29 11:37:32 -08:00
2011-09-18 11:19:35 +03:00
# 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 ,
2012-03-05 01:03:54 +01:00
struct sk_buff * skb )
2011-09-18 11:19:35 +03:00
{
struct nci_core_conn_credit_ntf * ntf = ( void * ) skb - > data ;
2015-02-01 22:26:08 +01:00
struct nci_conn_info * conn_info ;
2011-09-18 11:19:35 +03:00
int i ;
2011-11-29 11:37:35 -08:00
pr_debug ( " num_entries %d \n " , ntf - > num_entries ) ;
2011-09-18 11:19:35 +03:00
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 + + ) {
2011-12-20 16:57:40 +02:00
ntf - > conn_entries [ i ] . conn_id =
nci_conn_id ( & ntf - > conn_entries [ i ] . conn_id ) ;
2011-11-29 11:37:33 -08:00
pr_debug ( " entry[%d]: conn_id %d, credits %d \n " ,
i , ntf - > conn_entries [ i ] . conn_id ,
ntf - > conn_entries [ i ] . credits ) ;
2011-09-18 11:19:35 +03:00
2015-02-01 22:26:08 +01:00
conn_info = nci_get_conn_info_by_conn_id ( ndev ,
ntf - > conn_entries [ i ] . conn_id ) ;
if ( ! conn_info )
return ;
atomic_add ( ntf - > conn_entries [ i ] . credits ,
& conn_info - > credits_cnt ) ;
2011-09-18 11:19:35 +03:00
}
/* trigger the next tx */
if ( ! skb_queue_empty ( & ndev - > tx_q ) )
queue_work ( ndev - > tx_wq , & ndev - > tx_work ) ;
}
2012-01-18 13:16:14 +02:00
static void nci_core_generic_error_ntf_packet ( struct nci_dev * ndev ,
2012-03-05 01:03:54 +01:00
struct sk_buff * skb )
2012-01-18 13:16:14 +02:00
{
__u8 status = skb - > data [ 0 ] ;
pr_debug ( " status 0x%x \n " , status ) ;
if ( atomic_read ( & ndev - > state ) = = NCI_W4_HOST_SELECT ) {
/* Activation failed, so complete the request
2012-03-05 01:03:54 +01:00
( the state remains the same ) */
2012-01-18 13:16:14 +02:00
nci_req_complete ( ndev , status ) ;
}
}
2011-12-20 16:57:41 +02:00
static void nci_core_conn_intf_error_ntf_packet ( struct nci_dev * ndev ,
struct sk_buff * skb )
{
struct nci_core_intf_error_ntf * ntf = ( void * ) skb - > data ;
ntf - > conn_id = nci_conn_id ( & ntf - > conn_id ) ;
pr_debug ( " status 0x%x, conn_id %d \n " , ntf - > status , ntf - > conn_id ) ;
/* complete the data exchange transaction, if exists */
if ( test_bit ( NCI_DATA_EXCHANGE , & ndev - > flags ) )
2015-02-01 22:26:08 +01:00
nci_data_exchange_complete ( ndev , NULL , ntf - > conn_id , - EIO ) ;
2011-12-20 16:57:41 +02:00
}
2011-11-09 12:09:14 +02:00
static __u8 * nci_extract_rf_params_nfca_passive_poll ( struct nci_dev * ndev ,
2012-01-18 13:16:14 +02:00
struct rf_tech_specific_params_nfca_poll * nfca_poll ,
2012-03-05 01:03:54 +01:00
__u8 * data )
2011-09-18 11:19:35 +03:00
{
2014-12-02 21:27:58 +01:00
nfca_poll - > sens_res = __le16_to_cpu ( * ( ( __le16 * ) data ) ) ;
2011-09-18 11:19:35 +03:00
data + = 2 ;
2012-06-25 16:05:27 +02:00
nfca_poll - > nfcid1_len = min_t ( __u8 , * data + + , NFC_NFCID1_MAXSIZE ) ;
2011-09-18 11:19:35 +03:00
2011-11-29 11:37:33 -08:00
pr_debug ( " sens_res 0x%x, nfcid1_len %d \n " ,
nfca_poll - > sens_res , nfca_poll - > nfcid1_len ) ;
2011-09-18 11:19:35 +03:00
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 + + ;
2011-11-29 11:37:33 -08:00
pr_debug ( " sel_res_len %d, sel_res 0x%x \n " ,
nfca_poll - > sel_res_len ,
nfca_poll - > sel_res ) ;
2011-11-09 12:09:14 +02:00
return data ;
}
2012-01-17 11:06:43 +02:00
static __u8 * nci_extract_rf_params_nfcb_passive_poll ( struct nci_dev * ndev ,
2012-01-18 13:16:14 +02:00
struct rf_tech_specific_params_nfcb_poll * nfcb_poll ,
2012-03-05 01:03:54 +01:00
__u8 * data )
2012-01-17 11:06:43 +02:00
{
2012-06-25 16:05:27 +02:00
nfcb_poll - > sensb_res_len = min_t ( __u8 , * data + + , NFC_SENSB_RES_MAXSIZE ) ;
2012-01-17 11:06:43 +02:00
pr_debug ( " sensb_res_len %d \n " , nfcb_poll - > sensb_res_len ) ;
memcpy ( nfcb_poll - > sensb_res , data , nfcb_poll - > sensb_res_len ) ;
data + = nfcb_poll - > sensb_res_len ;
return data ;
}
static __u8 * nci_extract_rf_params_nfcf_passive_poll ( struct nci_dev * ndev ,
2012-01-18 13:16:14 +02:00
struct rf_tech_specific_params_nfcf_poll * nfcf_poll ,
2012-03-05 01:03:54 +01:00
__u8 * data )
2012-01-17 11:06:43 +02:00
{
nfcf_poll - > bit_rate = * data + + ;
2012-06-25 16:05:27 +02:00
nfcf_poll - > sensf_res_len = min_t ( __u8 , * data + + , NFC_SENSF_RES_MAXSIZE ) ;
2012-01-17 11:06:43 +02:00
pr_debug ( " bit_rate %d, sensf_res_len %d \n " ,
2012-03-05 01:03:54 +01:00
nfcf_poll - > bit_rate , nfcf_poll - > sensf_res_len ) ;
2012-01-17 11:06:43 +02:00
memcpy ( nfcf_poll - > sensf_res , data , nfcf_poll - > sensf_res_len ) ;
data + = nfcf_poll - > sensf_res_len ;
return data ;
}
2014-07-22 19:48:38 +02:00
static __u8 * nci_extract_rf_params_nfcv_passive_poll ( struct nci_dev * ndev ,
struct rf_tech_specific_params_nfcv_poll * nfcv_poll ,
__u8 * data )
{
+ + data ;
nfcv_poll - > dsfid = * data + + ;
memcpy ( nfcv_poll - > uid , data , NFC_ISO15693_UID_MAXSIZE ) ;
data + = NFC_ISO15693_UID_MAXSIZE ;
return data ;
}
2014-10-21 16:52:46 +02:00
static __u8 * nci_extract_rf_params_nfcf_passive_listen ( struct nci_dev * ndev ,
struct rf_tech_specific_params_nfcf_listen * nfcf_listen ,
__u8 * data )
{
nfcf_listen - > local_nfcid2_len = min_t ( __u8 , * data + + ,
NFC_NFCID2_MAXSIZE ) ;
memcpy ( nfcf_listen - > local_nfcid2 , data , nfcf_listen - > local_nfcid2_len ) ;
data + = nfcf_listen - > local_nfcid2_len ;
return data ;
}
2014-11-13 00:30:32 +01:00
static __u32 nci_get_prop_rf_protocol ( struct nci_dev * ndev , __u8 rf_protocol )
2014-09-13 10:28:49 +02:00
{
if ( ndev - > ops - > get_rfprotocol )
return ndev - > ops - > get_rfprotocol ( ndev , rf_protocol ) ;
return 0 ;
}
2012-01-18 13:16:14 +02:00
static int nci_add_new_protocol ( struct nci_dev * ndev ,
struct nfc_target * target ,
__u8 rf_protocol ,
__u8 rf_tech_and_mode ,
void * params )
{
struct rf_tech_specific_params_nfca_poll * nfca_poll ;
struct rf_tech_specific_params_nfcb_poll * nfcb_poll ;
struct rf_tech_specific_params_nfcf_poll * nfcf_poll ;
2014-07-22 19:48:38 +02:00
struct rf_tech_specific_params_nfcv_poll * nfcv_poll ;
2012-01-18 13:16:14 +02:00
__u32 protocol ;
2014-05-25 22:35:40 +02:00
if ( rf_protocol = = NCI_RF_PROTOCOL_T1T )
protocol = NFC_PROTO_JEWEL_MASK ;
else if ( rf_protocol = = NCI_RF_PROTOCOL_T2T )
2012-01-18 13:16:14 +02:00
protocol = NFC_PROTO_MIFARE_MASK ;
else if ( rf_protocol = = NCI_RF_PROTOCOL_ISO_DEP )
2012-07-04 00:14:04 +02:00
if ( rf_tech_and_mode = = NCI_NFC_A_PASSIVE_POLL_MODE )
protocol = NFC_PROTO_ISO14443_MASK ;
else
protocol = NFC_PROTO_ISO14443_B_MASK ;
2012-01-18 13:16:14 +02:00
else if ( rf_protocol = = NCI_RF_PROTOCOL_T3T )
protocol = NFC_PROTO_FELICA_MASK ;
2012-08-15 11:46:24 +03:00
else if ( rf_protocol = = NCI_RF_PROTOCOL_NFC_DEP )
protocol = NFC_PROTO_NFC_DEP_MASK ;
2014-07-22 19:48:38 +02:00
else if ( rf_protocol = = NCI_RF_PROTOCOL_T5T )
protocol = NFC_PROTO_ISO15693_MASK ;
2012-01-18 13:16:14 +02:00
else
2014-09-13 10:28:49 +02:00
protocol = nci_get_prop_rf_protocol ( ndev , rf_protocol ) ;
2012-01-18 13:16:14 +02:00
if ( ! ( protocol & ndev - > poll_prots ) ) {
pr_err ( " the target found does not have the desired protocol \n " ) ;
return - EPROTO ;
}
if ( rf_tech_and_mode = = NCI_NFC_A_PASSIVE_POLL_MODE ) {
nfca_poll = ( struct rf_tech_specific_params_nfca_poll * ) params ;
target - > sens_res = nfca_poll - > sens_res ;
target - > sel_res = nfca_poll - > sel_res ;
target - > nfcid1_len = nfca_poll - > nfcid1_len ;
if ( target - > nfcid1_len > 0 ) {
memcpy ( target - > nfcid1 , nfca_poll - > nfcid1 ,
2012-03-05 01:03:54 +01:00
target - > nfcid1_len ) ;
2012-01-18 13:16:14 +02:00
}
} else if ( rf_tech_and_mode = = NCI_NFC_B_PASSIVE_POLL_MODE ) {
nfcb_poll = ( struct rf_tech_specific_params_nfcb_poll * ) params ;
target - > sensb_res_len = nfcb_poll - > sensb_res_len ;
if ( target - > sensb_res_len > 0 ) {
memcpy ( target - > sensb_res , nfcb_poll - > sensb_res ,
2012-03-05 01:03:54 +01:00
target - > sensb_res_len ) ;
2012-01-18 13:16:14 +02:00
}
} else if ( rf_tech_and_mode = = NCI_NFC_F_PASSIVE_POLL_MODE ) {
nfcf_poll = ( struct rf_tech_specific_params_nfcf_poll * ) params ;
target - > sensf_res_len = nfcf_poll - > sensf_res_len ;
if ( target - > sensf_res_len > 0 ) {
memcpy ( target - > sensf_res , nfcf_poll - > sensf_res ,
2012-03-05 01:03:54 +01:00
target - > sensf_res_len ) ;
2012-01-18 13:16:14 +02:00
}
2014-07-22 19:48:38 +02:00
} else if ( rf_tech_and_mode = = NCI_NFC_V_PASSIVE_POLL_MODE ) {
nfcv_poll = ( struct rf_tech_specific_params_nfcv_poll * ) params ;
target - > is_iso15693 = 1 ;
target - > iso15693_dsfid = nfcv_poll - > dsfid ;
memcpy ( target - > iso15693_uid , nfcv_poll - > uid , NFC_ISO15693_UID_MAXSIZE ) ;
2012-01-18 13:16:14 +02:00
} else {
pr_err ( " unsupported rf_tech_and_mode 0x%x \n " , rf_tech_and_mode ) ;
return - EPROTO ;
}
target - > supported_protocols | = protocol ;
pr_debug ( " protocol 0x%x \n " , protocol ) ;
return 0 ;
}
static void nci_add_new_target ( struct nci_dev * ndev ,
2012-03-05 01:03:54 +01:00
struct nci_rf_discover_ntf * ntf )
2012-01-18 13:16:14 +02:00
{
struct nfc_target * target ;
int i , rc ;
for ( i = 0 ; i < ndev - > n_targets ; i + + ) {
target = & ndev - > targets [ i ] ;
2012-04-10 19:43:09 +02:00
if ( target - > logical_idx = = ntf - > rf_discovery_id ) {
2012-01-18 13:16:14 +02:00
/* This target already exists, add the new protocol */
nci_add_new_protocol ( ndev , target , ntf - > rf_protocol ,
2012-03-05 01:03:54 +01:00
ntf - > rf_tech_and_mode ,
& ntf - > rf_tech_specific_params ) ;
2012-01-18 13:16:14 +02:00
return ;
}
}
/* This is a new target, check if we've enough room */
if ( ndev - > n_targets = = NCI_MAX_DISCOVERED_TARGETS ) {
pr_debug ( " not enough room, ignoring new target... \n " ) ;
return ;
}
target = & ndev - > targets [ ndev - > n_targets ] ;
rc = nci_add_new_protocol ( ndev , target , ntf - > rf_protocol ,
2012-03-05 01:03:54 +01:00
ntf - > rf_tech_and_mode ,
& ntf - > rf_tech_specific_params ) ;
2012-01-18 13:16:14 +02:00
if ( ! rc ) {
2012-04-10 19:43:09 +02:00
target - > logical_idx = ntf - > rf_discovery_id ;
2012-01-18 13:16:14 +02:00
ndev - > n_targets + + ;
2012-04-10 19:43:09 +02:00
pr_debug ( " logical idx %d, n_targets %d \n " , target - > logical_idx ,
2012-03-05 01:03:54 +01:00
ndev - > n_targets ) ;
2012-01-18 13:16:14 +02:00
}
}
void nci_clear_target_list ( struct nci_dev * ndev )
{
memset ( ndev - > targets , 0 ,
2012-03-05 01:03:54 +01:00
( sizeof ( struct nfc_target ) * NCI_MAX_DISCOVERED_TARGETS ) ) ;
2012-01-18 13:16:14 +02:00
ndev - > n_targets = 0 ;
}
static void nci_rf_discover_ntf_packet ( struct nci_dev * ndev ,
2012-03-05 01:03:54 +01:00
struct sk_buff * skb )
2012-01-18 13:16:14 +02:00
{
struct nci_rf_discover_ntf ntf ;
__u8 * data = skb - > data ;
bool add_target = true ;
ntf . rf_discovery_id = * data + + ;
ntf . rf_protocol = * data + + ;
ntf . rf_tech_and_mode = * data + + ;
ntf . rf_tech_specific_params_len = * data + + ;
pr_debug ( " rf_discovery_id %d \n " , ntf . rf_discovery_id ) ;
pr_debug ( " rf_protocol 0x%x \n " , ntf . rf_protocol ) ;
pr_debug ( " rf_tech_and_mode 0x%x \n " , ntf . rf_tech_and_mode ) ;
pr_debug ( " rf_tech_specific_params_len %d \n " ,
2012-03-05 01:03:54 +01:00
ntf . rf_tech_specific_params_len ) ;
2012-01-18 13:16:14 +02:00
if ( ntf . rf_tech_specific_params_len > 0 ) {
switch ( ntf . rf_tech_and_mode ) {
case NCI_NFC_A_PASSIVE_POLL_MODE :
data = nci_extract_rf_params_nfca_passive_poll ( ndev ,
& ( ntf . rf_tech_specific_params . nfca_poll ) , data ) ;
break ;
case NCI_NFC_B_PASSIVE_POLL_MODE :
data = nci_extract_rf_params_nfcb_passive_poll ( ndev ,
& ( ntf . rf_tech_specific_params . nfcb_poll ) , data ) ;
break ;
case NCI_NFC_F_PASSIVE_POLL_MODE :
data = nci_extract_rf_params_nfcf_passive_poll ( ndev ,
& ( ntf . rf_tech_specific_params . nfcf_poll ) , data ) ;
break ;
2014-07-22 19:48:38 +02:00
case NCI_NFC_V_PASSIVE_POLL_MODE :
data = nci_extract_rf_params_nfcv_passive_poll ( ndev ,
& ( ntf . rf_tech_specific_params . nfcv_poll ) , data ) ;
break ;
2012-01-18 13:16:14 +02:00
default :
pr_err ( " unsupported rf_tech_and_mode 0x%x \n " ,
ntf . rf_tech_and_mode ) ;
data + = ntf . rf_tech_specific_params_len ;
add_target = false ;
}
}
ntf . ntf_type = * data + + ;
pr_debug ( " ntf_type %d \n " , ntf . ntf_type ) ;
if ( add_target = = true )
nci_add_new_target ( ndev , & ntf ) ;
if ( ntf . ntf_type = = NCI_DISCOVER_NTF_TYPE_MORE ) {
atomic_set ( & ndev - > state , NCI_W4_ALL_DISCOVERIES ) ;
} else {
atomic_set ( & ndev - > state , NCI_W4_HOST_SELECT ) ;
nfc_targets_found ( ndev - > nfc_dev , ndev - > targets ,
2012-03-05 01:03:54 +01:00
ndev - > n_targets ) ;
2012-01-18 13:16:14 +02:00
}
}
2011-11-09 12:09:14 +02:00
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 ;
2012-01-17 11:06:43 +02:00
struct activation_params_nfcb_poll_iso_dep * nfcb_poll ;
2011-11-09 12:09:14 +02:00
switch ( ntf - > activation_rf_tech_and_mode ) {
case NCI_NFC_A_PASSIVE_POLL_MODE :
nfca_poll = & ntf - > activation_params . nfca_poll_iso_dep ;
2012-06-25 16:05:27 +02:00
nfca_poll - > rats_res_len = min_t ( __u8 , * data + + , 20 ) ;
2012-01-17 11:06:43 +02:00
pr_debug ( " rats_res_len %d \n " , nfca_poll - > rats_res_len ) ;
2011-11-09 12:09:14 +02:00
if ( nfca_poll - > rats_res_len > 0 ) {
memcpy ( nfca_poll - > rats_res ,
2012-03-05 01:03:54 +01:00
data , nfca_poll - > rats_res_len ) ;
2011-09-18 11:19:35 +03:00
}
break ;
2012-01-17 11:06:43 +02:00
case NCI_NFC_B_PASSIVE_POLL_MODE :
nfcb_poll = & ntf - > activation_params . nfcb_poll_iso_dep ;
2012-06-25 16:05:27 +02:00
nfcb_poll - > attrib_res_len = min_t ( __u8 , * data + + , 50 ) ;
2012-03-05 01:03:54 +01:00
pr_debug ( " attrib_res_len %d \n " , nfcb_poll - > attrib_res_len ) ;
2012-01-17 11:06:43 +02:00
if ( nfcb_poll - > attrib_res_len > 0 ) {
memcpy ( nfcb_poll - > attrib_res ,
2012-03-05 01:03:54 +01:00
data , nfcb_poll - > attrib_res_len ) ;
2012-01-17 11:06:43 +02:00
}
break ;
2011-09-18 11:19:35 +03:00
default :
2011-11-29 11:37:32 -08:00
pr_err ( " unsupported activation_rf_tech_and_mode 0x%x \n " ,
ntf - > activation_rf_tech_and_mode ) ;
2012-01-18 13:16:14 +02:00
return NCI_STATUS_RF_PROTOCOL_ERROR ;
2011-09-18 11:19:35 +03:00
}
2012-01-18 13:16:14 +02:00
return NCI_STATUS_OK ;
2011-09-18 11:19:35 +03:00
}
2012-08-15 11:46:23 +03:00
static int nci_extract_activation_params_nfc_dep ( struct nci_dev * ndev ,
struct nci_rf_intf_activated_ntf * ntf , __u8 * data )
{
struct activation_params_poll_nfc_dep * poll ;
2014-10-21 16:52:46 +02:00
struct activation_params_listen_nfc_dep * listen ;
2012-08-15 11:46:23 +03:00
switch ( ntf - > activation_rf_tech_and_mode ) {
case NCI_NFC_A_PASSIVE_POLL_MODE :
case NCI_NFC_F_PASSIVE_POLL_MODE :
poll = & ntf - > activation_params . poll_nfc_dep ;
2014-10-21 16:52:46 +02:00
poll - > atr_res_len = min_t ( __u8 , * data + + ,
NFC_ATR_RES_MAXSIZE - 2 ) ;
2012-08-15 11:46:23 +03:00
pr_debug ( " atr_res_len %d \n " , poll - > atr_res_len ) ;
2014-05-06 15:51:50 +09:00
if ( poll - > atr_res_len > 0 )
memcpy ( poll - > atr_res , data , poll - > atr_res_len ) ;
2012-08-15 11:46:23 +03:00
break ;
2014-10-21 16:52:46 +02:00
case NCI_NFC_A_PASSIVE_LISTEN_MODE :
case NCI_NFC_F_PASSIVE_LISTEN_MODE :
listen = & ntf - > activation_params . listen_nfc_dep ;
listen - > atr_req_len = min_t ( __u8 , * data + + ,
NFC_ATR_REQ_MAXSIZE - 2 ) ;
pr_debug ( " atr_req_len %d \n " , listen - > atr_req_len ) ;
if ( listen - > atr_req_len > 0 )
memcpy ( listen - > atr_req , data , listen - > atr_req_len ) ;
break ;
2012-08-15 11:46:23 +03:00
default :
pr_err ( " unsupported activation_rf_tech_and_mode 0x%x \n " ,
ntf - > activation_rf_tech_and_mode ) ;
return NCI_STATUS_RF_PROTOCOL_ERROR ;
}
return NCI_STATUS_OK ;
}
2012-01-18 13:16:14 +02:00
static void nci_target_auto_activated ( struct nci_dev * ndev ,
2012-03-05 01:03:54 +01:00
struct nci_rf_intf_activated_ntf * ntf )
2011-09-18 11:19:35 +03:00
{
2012-01-18 13:16:14 +02:00
struct nfc_target * target ;
int rc ;
2011-09-18 11:19:35 +03:00
2012-01-18 13:16:14 +02:00
target = & ndev - > targets [ ndev - > n_targets ] ;
2012-01-17 11:06:43 +02:00
2012-01-18 13:16:14 +02:00
rc = nci_add_new_protocol ( ndev , target , ntf - > rf_protocol ,
2012-03-05 01:03:54 +01:00
ntf - > activation_rf_tech_and_mode ,
& ntf - > rf_tech_specific_params ) ;
2012-01-18 13:16:14 +02:00
if ( rc )
2011-09-18 11:19:35 +03:00
return ;
2012-04-10 19:43:09 +02:00
target - > logical_idx = ntf - > rf_discovery_id ;
2012-01-18 13:16:14 +02:00
ndev - > n_targets + + ;
2012-01-17 11:06:43 +02:00
2012-04-10 19:43:09 +02:00
pr_debug ( " logical idx %d, n_targets %d \n " ,
target - > logical_idx , ndev - > n_targets ) ;
2011-12-20 16:57:40 +02:00
2012-01-18 13:16:14 +02:00
nfc_targets_found ( ndev - > nfc_dev , ndev - > targets , ndev - > n_targets ) ;
2011-09-18 11:19:35 +03:00
}
2014-10-21 16:52:46 +02:00
static int nci_store_general_bytes_nfc_dep ( struct nci_dev * ndev ,
struct nci_rf_intf_activated_ntf * ntf )
{
ndev - > remote_gb_len = 0 ;
if ( ntf - > activation_params_len < = 0 )
return NCI_STATUS_OK ;
switch ( ntf - > activation_rf_tech_and_mode ) {
case NCI_NFC_A_PASSIVE_POLL_MODE :
case NCI_NFC_F_PASSIVE_POLL_MODE :
ndev - > remote_gb_len = min_t ( __u8 ,
( ntf - > activation_params . poll_nfc_dep . atr_res_len
- NFC_ATR_RES_GT_OFFSET ) ,
2014-12-02 16:25:01 +01:00
NFC_ATR_RES_GB_MAXSIZE ) ;
2014-10-21 16:52:46 +02:00
memcpy ( ndev - > remote_gb ,
2014-12-02 16:25:01 +01:00
( ntf - > activation_params . poll_nfc_dep . atr_res
2014-10-21 16:52:46 +02:00
+ NFC_ATR_RES_GT_OFFSET ) ,
ndev - > remote_gb_len ) ;
break ;
case NCI_NFC_A_PASSIVE_LISTEN_MODE :
case NCI_NFC_F_PASSIVE_LISTEN_MODE :
ndev - > remote_gb_len = min_t ( __u8 ,
( ntf - > activation_params . listen_nfc_dep . atr_req_len
- NFC_ATR_REQ_GT_OFFSET ) ,
2014-12-02 16:25:01 +01:00
NFC_ATR_REQ_GB_MAXSIZE ) ;
2014-10-21 16:52:46 +02:00
memcpy ( ndev - > remote_gb ,
( ntf - > activation_params . listen_nfc_dep . atr_req
+ NFC_ATR_REQ_GT_OFFSET ) ,
ndev - > remote_gb_len ) ;
break ;
default :
pr_err ( " unsupported activation_rf_tech_and_mode 0x%x \n " ,
ntf - > activation_rf_tech_and_mode ) ;
return NCI_STATUS_RF_PROTOCOL_ERROR ;
}
return NCI_STATUS_OK ;
}
2011-11-09 12:09:14 +02:00
static void nci_rf_intf_activated_ntf_packet ( struct nci_dev * ndev ,
2012-03-05 01:03:54 +01:00
struct sk_buff * skb )
2011-09-18 11:19:35 +03:00
{
2015-02-01 22:26:08 +01:00
struct nci_conn_info * conn_info ;
2011-11-09 12:09:14 +02:00
struct nci_rf_intf_activated_ntf ntf ;
2011-09-18 11:19:35 +03:00
__u8 * data = skb - > data ;
2012-01-18 13:16:14 +02:00
int err = NCI_STATUS_OK ;
2011-09-18 11:19:35 +03:00
2011-11-09 12:09:14 +02:00
ntf . rf_discovery_id = * data + + ;
2011-12-20 16:57:40 +02:00
ntf . rf_interface = * data + + ;
2011-09-18 11:19:35 +03:00
ntf . rf_protocol = * data + + ;
2011-11-09 12:09:14 +02:00
ntf . activation_rf_tech_and_mode = * data + + ;
2011-12-20 16:57:40 +02:00
ntf . max_data_pkt_payload_size = * data + + ;
ntf . initial_num_credits = * data + + ;
2011-09-18 11:19:35 +03:00
ntf . rf_tech_specific_params_len = * data + + ;
2011-11-29 11:37:33 -08:00
pr_debug ( " rf_discovery_id %d \n " , ntf . rf_discovery_id ) ;
2011-12-20 16:57:40 +02:00
pr_debug ( " rf_interface 0x%x \n " , ntf . rf_interface ) ;
2011-11-29 11:37:33 -08:00
pr_debug ( " rf_protocol 0x%x \n " , ntf . rf_protocol ) ;
pr_debug ( " activation_rf_tech_and_mode 0x%x \n " ,
ntf . activation_rf_tech_and_mode ) ;
2011-12-20 16:57:40 +02:00
pr_debug ( " max_data_pkt_payload_size 0x%x \n " ,
ntf . max_data_pkt_payload_size ) ;
2012-03-05 01:03:54 +01:00
pr_debug ( " initial_num_credits 0x%x \n " ,
ntf . initial_num_credits ) ;
2011-11-29 11:37:33 -08:00
pr_debug ( " rf_tech_specific_params_len %d \n " ,
ntf . rf_tech_specific_params_len ) ;
2011-09-18 11:19:35 +03:00
2015-02-01 22:26:18 +01:00
/* If this contains a value of 0x00 (NFCEE Direct RF
* Interface ) then all following parameters SHALL contain a
* value of 0 and SHALL be ignored .
*/
if ( ntf . rf_interface = = NCI_RF_INTERFACE_NFCEE_DIRECT )
goto listen ;
2011-11-09 12:09:14 +02:00
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 ,
2012-01-18 13:16:14 +02:00
& ( ntf . rf_tech_specific_params . nfca_poll ) , data ) ;
2011-11-09 12:09:14 +02:00
break ;
2012-01-17 11:06:43 +02:00
case NCI_NFC_B_PASSIVE_POLL_MODE :
data = nci_extract_rf_params_nfcb_passive_poll ( ndev ,
2012-01-18 13:16:14 +02:00
& ( ntf . rf_tech_specific_params . nfcb_poll ) , data ) ;
2012-01-17 11:06:43 +02:00
break ;
case NCI_NFC_F_PASSIVE_POLL_MODE :
data = nci_extract_rf_params_nfcf_passive_poll ( ndev ,
2012-01-18 13:16:14 +02:00
& ( ntf . rf_tech_specific_params . nfcf_poll ) , data ) ;
2012-01-17 11:06:43 +02:00
break ;
2014-07-22 19:48:38 +02:00
case NCI_NFC_V_PASSIVE_POLL_MODE :
data = nci_extract_rf_params_nfcv_passive_poll ( ndev ,
& ( ntf . rf_tech_specific_params . nfcv_poll ) , data ) ;
break ;
2014-10-21 16:52:46 +02:00
case NCI_NFC_A_PASSIVE_LISTEN_MODE :
/* no RF technology specific parameters */
break ;
case NCI_NFC_F_PASSIVE_LISTEN_MODE :
data = nci_extract_rf_params_nfcf_passive_listen ( ndev ,
& ( ntf . rf_tech_specific_params . nfcf_listen ) ,
data ) ;
break ;
2011-11-09 12:09:14 +02:00
default :
2011-11-29 11:37:32 -08:00
pr_err ( " unsupported activation_rf_tech_and_mode 0x%x \n " ,
ntf . activation_rf_tech_and_mode ) ;
2012-01-18 13:16:14 +02:00
err = NCI_STATUS_RF_PROTOCOL_ERROR ;
goto exit ;
2011-11-09 12:09:14 +02:00
}
}
2011-09-18 11:19:35 +03:00
2011-11-09 12:09:14 +02:00
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 + + ;
2011-11-29 11:37:33 -08:00
pr_debug ( " data_exch_rf_tech_and_mode 0x%x \n " ,
ntf . data_exch_rf_tech_and_mode ) ;
2012-03-05 01:03:54 +01:00
pr_debug ( " data_exch_tx_bit_rate 0x%x \n " , ntf . data_exch_tx_bit_rate ) ;
pr_debug ( " data_exch_rx_bit_rate 0x%x \n " , ntf . data_exch_rx_bit_rate ) ;
pr_debug ( " activation_params_len %d \n " , ntf . activation_params_len ) ;
2011-11-09 12:09:14 +02:00
if ( ntf . activation_params_len > 0 ) {
2011-12-20 16:57:40 +02:00
switch ( ntf . rf_interface ) {
2011-11-09 12:09:14 +02:00
case NCI_RF_INTERFACE_ISO_DEP :
err = nci_extract_activation_params_iso_dep ( ndev ,
2012-03-05 01:03:54 +01:00
& ntf , data ) ;
2011-11-09 12:09:14 +02:00
break ;
2012-08-15 11:46:23 +03:00
case NCI_RF_INTERFACE_NFC_DEP :
err = nci_extract_activation_params_nfc_dep ( ndev ,
& ntf , data ) ;
break ;
2011-11-09 12:09:14 +02:00
case NCI_RF_INTERFACE_FRAME :
/* no activation params */
break ;
default :
2011-12-20 16:57:40 +02:00
pr_err ( " unsupported rf_interface 0x%x \n " ,
ntf . rf_interface ) ;
2012-01-18 13:16:14 +02:00
err = NCI_STATUS_RF_PROTOCOL_ERROR ;
break ;
2011-11-09 12:09:14 +02:00
}
2011-09-18 11:19:35 +03:00
}
2012-01-18 13:16:14 +02:00
exit :
if ( err = = NCI_STATUS_OK ) {
2015-02-03 19:48:04 +01:00
conn_info = ndev - > rf_conn_info ;
2015-02-01 22:26:08 +01:00
if ( ! conn_info )
return ;
conn_info - > max_pkt_payload_len = ntf . max_data_pkt_payload_size ;
conn_info - > initial_num_credits = ntf . initial_num_credits ;
2012-01-18 13:16:14 +02:00
/* set the available credits to initial value */
2015-02-01 22:26:08 +01:00
atomic_set ( & conn_info - > credits_cnt ,
conn_info - > initial_num_credits ) ;
2012-08-15 11:46:24 +03:00
/* store general bytes to be reported later in dep_link_up */
if ( ntf . rf_interface = = NCI_RF_INTERFACE_NFC_DEP ) {
2014-10-21 16:52:46 +02:00
err = nci_store_general_bytes_nfc_dep ( ndev , & ntf ) ;
if ( err ! = NCI_STATUS_OK )
pr_err ( " unable to store general bytes \n " ) ;
2012-08-15 11:46:24 +03:00
}
2012-01-18 13:16:14 +02:00
}
2014-10-21 16:52:46 +02:00
if ( ! ( ntf . activation_rf_tech_and_mode & NCI_RF_TECH_MODE_LISTEN_MASK ) ) {
/* Poll mode */
if ( atomic_read ( & ndev - > state ) = = NCI_DISCOVERY ) {
/* A single target was found and activated
* automatically */
atomic_set ( & ndev - > state , NCI_POLL_ACTIVE ) ;
if ( err = = NCI_STATUS_OK )
nci_target_auto_activated ( ndev , & ntf ) ;
} else { /* ndev->state == NCI_W4_HOST_SELECT */
/* A selected target was activated, so complete the
* request */
atomic_set ( & ndev - > state , NCI_POLL_ACTIVE ) ;
nci_req_complete ( ndev , err ) ;
}
} else {
2015-02-01 22:26:18 +01:00
listen :
2014-10-21 16:52:46 +02:00
/* Listen mode */
atomic_set ( & ndev - > state , NCI_LISTEN_ACTIVE ) ;
if ( err = = NCI_STATUS_OK & &
ntf . rf_protocol = = NCI_RF_PROTOCOL_NFC_DEP ) {
err = nfc_tm_activated ( ndev - > nfc_dev ,
NFC_PROTO_NFC_DEP_MASK ,
NFC_COMM_PASSIVE ,
ndev - > remote_gb ,
ndev - > remote_gb_len ) ;
if ( err ! = NCI_STATUS_OK )
pr_err ( " error when signaling tm activation \n " ) ;
}
2012-01-18 13:16:14 +02:00
}
2011-09-18 11:19:35 +03:00
}
static void nci_rf_deactivate_ntf_packet ( struct nci_dev * ndev ,
2012-03-05 01:03:54 +01:00
struct sk_buff * skb )
2011-09-18 11:19:35 +03:00
{
2015-02-01 22:26:08 +01:00
struct nci_conn_info * conn_info ;
2011-11-09 12:09:14 +02:00
struct nci_rf_deactivate_ntf * ntf = ( void * ) skb - > data ;
2011-09-18 11:19:35 +03:00
2011-11-29 11:37:33 -08:00
pr_debug ( " entry, type 0x%x, reason 0x%x \n " , ntf - > type , ntf - > reason ) ;
2011-09-18 11:19:35 +03:00
2015-02-03 19:48:04 +01:00
conn_info = ndev - > rf_conn_info ;
2015-02-01 22:26:08 +01:00
if ( ! conn_info )
return ;
2011-09-18 11:19:35 +03:00
/* 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 ) ;
2012-05-07 12:31:26 +02:00
ndev - > rx_data_reassembly = NULL ;
2011-09-18 11:19:35 +03:00
}
/* complete the data exchange transaction, if exists */
2011-09-22 11:36:19 +03:00
if ( test_bit ( NCI_DATA_EXCHANGE , & ndev - > flags ) )
2015-02-01 22:26:08 +01:00
nci_data_exchange_complete ( ndev , NULL , NCI_STATIC_RF_CONN_ID ,
- EIO ) ;
2012-01-08 11:21:53 +02:00
2014-12-02 21:27:48 +01:00
switch ( ntf - > type ) {
case NCI_DEACTIVATE_TYPE_IDLE_MODE :
nci_clear_target_list ( ndev ) ;
2014-10-21 16:52:52 +02:00
atomic_set ( & ndev - > state , NCI_IDLE ) ;
2014-12-02 21:27:48 +01:00
break ;
case NCI_DEACTIVATE_TYPE_SLEEP_MODE :
case NCI_DEACTIVATE_TYPE_SLEEP_AF_MODE :
atomic_set ( & ndev - > state , NCI_W4_HOST_SELECT ) ;
break ;
case NCI_DEACTIVATE_TYPE_DISCOVERY :
nci_clear_target_list ( ndev ) ;
atomic_set ( & ndev - > state , NCI_DISCOVERY ) ;
break ;
}
2012-01-08 11:21:53 +02:00
nci_req_complete ( ndev , NCI_STATUS_OK ) ;
2011-09-18 11:19:35 +03:00
}
2015-02-01 22:26:10 +01:00
static void nci_nfcee_discover_ntf_packet ( struct nci_dev * ndev ,
struct sk_buff * skb )
{
u8 status = NCI_STATUS_OK ;
struct nci_nfcee_discover_ntf * nfcee_ntf =
( struct nci_nfcee_discover_ntf * ) skb - > data ;
pr_debug ( " \n " ) ;
2015-02-01 22:26:14 +01:00
/* NFCForum NCI 9.2.1 HCI Network Specific Handling
* If the NFCC supports the HCI Network , it SHALL return one ,
* and only one , NFCEE_DISCOVER_NTF with a Protocol type of
* “ HCI Access ” , even if the HCI Network contains multiple NFCEEs .
*/
2015-02-03 19:48:07 +01:00
ndev - > hci_dev - > nfcee_id = nfcee_ntf - > nfcee_id ;
2016-04-30 09:12:51 +02:00
ndev - > cur_params . id = nfcee_ntf - > nfcee_id ;
2015-02-01 22:26:14 +01:00
2015-02-01 22:26:10 +01:00
nci_req_complete ( ndev , status ) ;
}
2015-02-01 22:26:17 +01:00
static void nci_nfcee_action_ntf_packet ( struct nci_dev * ndev ,
struct sk_buff * skb )
{
pr_debug ( " \n " ) ;
}
2011-09-18 11:19:35 +03:00
void nci_ntf_packet ( struct nci_dev * ndev , struct sk_buff * skb )
{
__u16 ntf_opcode = nci_opcode ( skb - > data ) ;
2011-11-29 11:37:33 -08:00
pr_debug ( " NCI RX: MT=ntf, PBF=%d, GID=0x%x, OID=0x%x, plen=%d \n " ,
nci_pbf ( skb - > data ) ,
nci_opcode_gid ( ntf_opcode ) ,
nci_opcode_oid ( ntf_opcode ) ,
nci_plen ( skb - > data ) ) ;
2011-09-18 11:19:35 +03:00
/* strip the nci control header */
skb_pull ( skb , NCI_CTRL_HDR_SIZE ) ;
2015-06-06 13:16:37 +02:00
if ( nci_opcode_gid ( ntf_opcode ) = = NCI_GID_PROPRIETARY ) {
2015-10-22 12:11:38 +03:00
if ( nci_prop_ntf_packet ( ndev , ntf_opcode , skb ) = = - ENOTSUPP ) {
2015-06-06 13:16:37 +02:00
pr_err ( " unsupported ntf opcode 0x%x \n " ,
ntf_opcode ) ;
}
goto end ;
}
2011-09-18 11:19:35 +03:00
switch ( ntf_opcode ) {
case NCI_OP_CORE_CONN_CREDITS_NTF :
nci_core_conn_credits_ntf_packet ( ndev , skb ) ;
break ;
2012-01-18 13:16:14 +02:00
case NCI_OP_CORE_GENERIC_ERROR_NTF :
nci_core_generic_error_ntf_packet ( ndev , skb ) ;
break ;
2011-12-20 16:57:41 +02:00
case NCI_OP_CORE_INTF_ERROR_NTF :
nci_core_conn_intf_error_ntf_packet ( ndev , skb ) ;
break ;
2012-01-18 13:16:14 +02:00
case NCI_OP_RF_DISCOVER_NTF :
nci_rf_discover_ntf_packet ( ndev , skb ) ;
break ;
2011-11-09 12:09:14 +02:00
case NCI_OP_RF_INTF_ACTIVATED_NTF :
nci_rf_intf_activated_ntf_packet ( ndev , skb ) ;
2011-09-18 11:19:35 +03:00
break ;
case NCI_OP_RF_DEACTIVATE_NTF :
nci_rf_deactivate_ntf_packet ( ndev , skb ) ;
break ;
2015-02-01 22:26:10 +01:00
case NCI_OP_NFCEE_DISCOVER_NTF :
nci_nfcee_discover_ntf_packet ( ndev , skb ) ;
break ;
2015-02-01 22:26:17 +01:00
case NCI_OP_RF_NFCEE_ACTION_NTF :
nci_nfcee_action_ntf_packet ( ndev , skb ) ;
break ;
2011-09-18 11:19:35 +03:00
default :
2011-11-29 11:37:32 -08:00
pr_err ( " unknown ntf opcode 0x%x \n " , ntf_opcode ) ;
2011-09-18 11:19:35 +03:00
break ;
}
2015-10-22 12:11:38 +03:00
nci_core_ntf_packet ( ndev , ntf_opcode , skb ) ;
2015-06-06 13:16:37 +02:00
end :
2011-09-18 11:19:35 +03:00
kfree_skb ( skb ) ;
}