2013-09-19 19:55:29 +04:00
/*
* NFC Digital Protocol stack
* Copyright ( c ) 2013 , Intel Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope 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 .
*
*/
2013-09-20 11:05:48 +04:00
# define pr_fmt(fmt) "digital: %s: " fmt, __func__
2013-09-19 19:55:29 +04:00
# include "digital.h"
# define DIGITAL_NFC_DEP_FRAME_DIR_OUT 0xD4
# define DIGITAL_NFC_DEP_FRAME_DIR_IN 0xD5
# define DIGITAL_NFC_DEP_NFCA_SOD_SB 0xF0
# define DIGITAL_CMD_ATR_REQ 0x00
# define DIGITAL_CMD_ATR_RES 0x01
# define DIGITAL_CMD_PSL_REQ 0x04
# define DIGITAL_CMD_PSL_RES 0x05
# define DIGITAL_CMD_DEP_REQ 0x06
# define DIGITAL_CMD_DEP_RES 0x07
# define DIGITAL_ATR_REQ_MIN_SIZE 16
# define DIGITAL_ATR_REQ_MAX_SIZE 64
2014-09-24 03:38:05 +04:00
# define DIGITAL_DID_MAX 14
2013-09-19 19:55:29 +04:00
# define DIGITAL_LR_BITS_PAYLOAD_SIZE_254B 0x30
2014-07-23 07:18:01 +04:00
# define DIGITAL_FSL_BITS_PAYLOAD_SIZE_254B \
( DIGITAL_LR_BITS_PAYLOAD_SIZE_254B > > 4 )
2013-09-19 19:55:29 +04:00
# define DIGITAL_GB_BIT 0x02
# define DIGITAL_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0)
# define DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT 0x10
2014-09-24 03:38:05 +04:00
# define DIGITAL_NFC_DEP_PFB_DID_BIT 0x04
2013-09-19 19:55:29 +04:00
# define DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb) \
( ( pfb ) & DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT )
# define DIGITAL_NFC_DEP_MI_BIT_SET(pfb) ((pfb) & 0x10)
# define DIGITAL_NFC_DEP_NAD_BIT_SET(pfb) ((pfb) & 0x08)
2014-09-24 03:38:05 +04:00
# define DIGITAL_NFC_DEP_DID_BIT_SET(pfb) ((pfb) & DIGITAL_NFC_DEP_PFB_DID_BIT)
2013-09-19 19:55:29 +04:00
# define DIGITAL_NFC_DEP_PFB_PNI(pfb) ((pfb) & 0x03)
# define DIGITAL_NFC_DEP_PFB_I_PDU 0x00
# define DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU 0x40
# define DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU 0x80
struct digital_atr_req {
u8 dir ;
u8 cmd ;
u8 nfcid3 [ 10 ] ;
u8 did ;
u8 bs ;
u8 br ;
u8 pp ;
u8 gb [ 0 ] ;
} __packed ;
struct digital_atr_res {
u8 dir ;
u8 cmd ;
u8 nfcid3 [ 10 ] ;
u8 did ;
u8 bs ;
u8 br ;
u8 to ;
u8 pp ;
u8 gb [ 0 ] ;
} __packed ;
struct digital_psl_req {
u8 dir ;
u8 cmd ;
u8 did ;
u8 brs ;
u8 fsl ;
} __packed ;
struct digital_psl_res {
u8 dir ;
u8 cmd ;
u8 did ;
} __packed ;
struct digital_dep_req_res {
u8 dir ;
u8 cmd ;
u8 pfb ;
} __packed ;
static void digital_in_recv_dep_res ( struct nfc_digital_dev * ddev , void * arg ,
struct sk_buff * resp ) ;
static void digital_skb_push_dep_sod ( struct nfc_digital_dev * ddev ,
struct sk_buff * skb )
{
skb_push ( skb , sizeof ( u8 ) ) ;
skb - > data [ 0 ] = skb - > len ;
if ( ddev - > curr_rf_tech = = NFC_DIGITAL_RF_TECH_106A )
* skb_push ( skb , sizeof ( u8 ) ) = DIGITAL_NFC_DEP_NFCA_SOD_SB ;
}
static int digital_skb_pull_dep_sod ( struct nfc_digital_dev * ddev ,
struct sk_buff * skb )
{
u8 size ;
if ( skb - > len < 2 )
return - EIO ;
if ( ddev - > curr_rf_tech = = NFC_DIGITAL_RF_TECH_106A )
skb_pull ( skb , sizeof ( u8 ) ) ;
size = skb - > data [ 0 ] ;
if ( size ! = skb - > len )
return - EIO ;
skb_pull ( skb , sizeof ( u8 ) ) ;
return 0 ;
}
2014-07-23 07:18:01 +04:00
static void digital_in_recv_psl_res ( struct nfc_digital_dev * ddev , void * arg ,
struct sk_buff * resp )
{
struct nfc_target * target = arg ;
struct digital_psl_res * psl_res ;
int rc ;
if ( IS_ERR ( resp ) ) {
rc = PTR_ERR ( resp ) ;
resp = NULL ;
goto exit ;
}
rc = ddev - > skb_check_crc ( resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.6 " ) ;
goto exit ;
}
rc = digital_skb_pull_dep_sod ( ddev , resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.2 " ) ;
goto exit ;
}
psl_res = ( struct digital_psl_res * ) resp - > data ;
if ( ( resp - > len ! = sizeof ( * psl_res ) ) | |
( psl_res - > dir ! = DIGITAL_NFC_DEP_FRAME_DIR_IN ) | |
( psl_res - > cmd ! = DIGITAL_CMD_PSL_RES ) ) {
rc = - EIO ;
goto exit ;
}
rc = digital_in_configure_hw ( ddev , NFC_DIGITAL_CONFIG_RF_TECH ,
NFC_DIGITAL_RF_TECH_424F ) ;
if ( rc )
goto exit ;
rc = digital_in_configure_hw ( ddev , NFC_DIGITAL_CONFIG_FRAMING ,
NFC_DIGITAL_FRAMING_NFCF_NFC_DEP ) ;
if ( rc )
goto exit ;
if ( ! DIGITAL_DRV_CAPS_IN_CRC ( ddev ) & &
( ddev - > curr_rf_tech = = NFC_DIGITAL_RF_TECH_106A ) ) {
ddev - > skb_add_crc = digital_skb_add_crc_f ;
ddev - > skb_check_crc = digital_skb_check_crc_f ;
}
ddev - > curr_rf_tech = NFC_DIGITAL_RF_TECH_424F ;
nfc_dep_link_is_up ( ddev - > nfc_dev , target - > idx , NFC_COMM_ACTIVE ,
NFC_RF_INITIATOR ) ;
ddev - > curr_nfc_dep_pni = 0 ;
exit :
dev_kfree_skb ( resp ) ;
if ( rc )
ddev - > curr_protocol = 0 ;
}
static int digital_in_send_psl_req ( struct nfc_digital_dev * ddev ,
struct nfc_target * target )
{
struct sk_buff * skb ;
struct digital_psl_req * psl_req ;
2014-09-24 03:38:02 +04:00
int rc ;
2014-07-23 07:18:01 +04:00
skb = digital_skb_alloc ( ddev , sizeof ( * psl_req ) ) ;
if ( ! skb )
return - ENOMEM ;
skb_put ( skb , sizeof ( * psl_req ) ) ;
psl_req = ( struct digital_psl_req * ) skb - > data ;
psl_req - > dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT ;
psl_req - > cmd = DIGITAL_CMD_PSL_REQ ;
psl_req - > did = 0 ;
psl_req - > brs = ( 0x2 < < 3 ) | 0x2 ; /* 424F both directions */
psl_req - > fsl = DIGITAL_FSL_BITS_PAYLOAD_SIZE_254B ;
digital_skb_push_dep_sod ( ddev , skb ) ;
ddev - > skb_add_crc ( skb ) ;
2014-09-24 03:38:02 +04:00
rc = digital_in_send_cmd ( ddev , skb , 500 , digital_in_recv_psl_res ,
target ) ;
if ( rc )
kfree_skb ( skb ) ;
return rc ;
2014-07-23 07:18:01 +04:00
}
2013-09-19 19:55:29 +04:00
static void digital_in_recv_atr_res ( struct nfc_digital_dev * ddev , void * arg ,
struct sk_buff * resp )
{
struct nfc_target * target = arg ;
struct digital_atr_res * atr_res ;
u8 gb_len ;
int rc ;
if ( IS_ERR ( resp ) ) {
rc = PTR_ERR ( resp ) ;
resp = NULL ;
goto exit ;
}
rc = ddev - > skb_check_crc ( resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.6 " ) ;
goto exit ;
}
rc = digital_skb_pull_dep_sod ( ddev , resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.2 " ) ;
goto exit ;
}
if ( resp - > len < sizeof ( struct digital_atr_res ) ) {
rc = - EIO ;
goto exit ;
}
gb_len = resp - > len - sizeof ( struct digital_atr_res ) ;
atr_res = ( struct digital_atr_res * ) resp - > data ;
rc = nfc_set_remote_general_bytes ( ddev - > nfc_dev , atr_res - > gb , gb_len ) ;
if ( rc )
goto exit ;
2014-07-23 07:18:01 +04:00
if ( ( ddev - > protocols & NFC_PROTO_FELICA_MASK ) & &
( ddev - > curr_rf_tech ! = NFC_DIGITAL_RF_TECH_424F ) ) {
rc = digital_in_send_psl_req ( ddev , target ) ;
if ( ! rc )
goto exit ;
}
2013-09-19 19:55:29 +04:00
rc = nfc_dep_link_is_up ( ddev - > nfc_dev , target - > idx , NFC_COMM_ACTIVE ,
NFC_RF_INITIATOR ) ;
ddev - > curr_nfc_dep_pni = 0 ;
exit :
dev_kfree_skb ( resp ) ;
if ( rc )
ddev - > curr_protocol = 0 ;
}
int digital_in_send_atr_req ( struct nfc_digital_dev * ddev ,
struct nfc_target * target , __u8 comm_mode , __u8 * gb ,
size_t gb_len )
{
struct sk_buff * skb ;
struct digital_atr_req * atr_req ;
uint size ;
2014-09-24 03:38:02 +04:00
int rc ;
2013-09-19 19:55:29 +04:00
size = DIGITAL_ATR_REQ_MIN_SIZE + gb_len ;
if ( size > DIGITAL_ATR_REQ_MAX_SIZE ) {
PROTOCOL_ERR ( " 14.6.1.1 " ) ;
return - EINVAL ;
}
skb = digital_skb_alloc ( ddev , size ) ;
if ( ! skb )
return - ENOMEM ;
skb_put ( skb , sizeof ( struct digital_atr_req ) ) ;
atr_req = ( struct digital_atr_req * ) skb - > data ;
memset ( atr_req , 0 , sizeof ( struct digital_atr_req ) ) ;
atr_req - > dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT ;
atr_req - > cmd = DIGITAL_CMD_ATR_REQ ;
if ( target - > nfcid2_len )
2014-01-02 14:58:14 +04:00
memcpy ( atr_req - > nfcid3 , target - > nfcid2 , NFC_NFCID2_MAXSIZE ) ;
2013-09-19 19:55:29 +04:00
else
2014-01-02 14:58:14 +04:00
get_random_bytes ( atr_req - > nfcid3 , NFC_NFCID3_MAXSIZE ) ;
2013-09-19 19:55:29 +04:00
atr_req - > did = 0 ;
atr_req - > bs = 0 ;
atr_req - > br = 0 ;
atr_req - > pp = DIGITAL_LR_BITS_PAYLOAD_SIZE_254B ;
if ( gb_len ) {
atr_req - > pp | = DIGITAL_GB_BIT ;
memcpy ( skb_put ( skb , gb_len ) , gb , gb_len ) ;
}
digital_skb_push_dep_sod ( ddev , skb ) ;
ddev - > skb_add_crc ( skb ) ;
2014-09-24 03:38:02 +04:00
rc = digital_in_send_cmd ( ddev , skb , 500 , digital_in_recv_atr_res ,
target ) ;
if ( rc )
kfree_skb ( skb ) ;
return rc ;
2013-09-19 19:55:29 +04:00
}
static int digital_in_send_rtox ( struct nfc_digital_dev * ddev ,
struct digital_data_exch * data_exch , u8 rtox )
{
struct digital_dep_req_res * dep_req ;
struct sk_buff * skb ;
int rc ;
skb = digital_skb_alloc ( ddev , 1 ) ;
if ( ! skb )
return - ENOMEM ;
* skb_put ( skb , 1 ) = rtox ;
skb_push ( skb , sizeof ( struct digital_dep_req_res ) ) ;
dep_req = ( struct digital_dep_req_res * ) skb - > data ;
dep_req - > dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT ;
dep_req - > cmd = DIGITAL_CMD_DEP_REQ ;
dep_req - > pfb = DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU |
DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT ;
digital_skb_push_dep_sod ( ddev , skb ) ;
ddev - > skb_add_crc ( skb ) ;
rc = digital_in_send_cmd ( ddev , skb , 1500 , digital_in_recv_dep_res ,
data_exch ) ;
2014-09-24 03:38:02 +04:00
if ( rc )
kfree_skb ( skb ) ;
2013-09-19 19:55:29 +04:00
return rc ;
}
static void digital_in_recv_dep_res ( struct nfc_digital_dev * ddev , void * arg ,
struct sk_buff * resp )
{
struct digital_data_exch * data_exch = arg ;
struct digital_dep_req_res * dep_res ;
u8 pfb ;
uint size ;
int rc ;
if ( IS_ERR ( resp ) ) {
rc = PTR_ERR ( resp ) ;
resp = NULL ;
goto exit ;
}
rc = ddev - > skb_check_crc ( resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.6 " ) ;
goto error ;
}
rc = digital_skb_pull_dep_sod ( ddev , resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.2 " ) ;
goto exit ;
}
2014-09-24 03:38:03 +04:00
size = sizeof ( struct digital_dep_req_res ) ;
2013-09-19 19:55:29 +04:00
dep_res = ( struct digital_dep_req_res * ) resp - > data ;
2014-09-24 03:38:03 +04:00
if ( resp - > len < size | | dep_res - > dir ! = DIGITAL_NFC_DEP_FRAME_DIR_IN | |
2013-09-19 19:55:29 +04:00
dep_res - > cmd ! = DIGITAL_CMD_DEP_RES ) {
rc = - EIO ;
goto error ;
}
pfb = dep_res - > pfb ;
2014-09-24 03:38:04 +04:00
if ( DIGITAL_NFC_DEP_DID_BIT_SET ( pfb ) ) {
PROTOCOL_ERR ( " 14.8.2.1 " ) ;
rc = - EIO ;
goto error ;
}
2014-09-24 03:38:03 +04:00
2014-09-24 03:38:06 +04:00
if ( DIGITAL_NFC_DEP_NAD_BIT_SET ( pfb ) ) {
rc = - EIO ;
goto exit ;
}
2014-09-24 03:38:03 +04:00
if ( size > resp - > len ) {
rc = - EIO ;
goto error ;
}
skb_pull ( resp , size ) ;
2013-09-19 19:55:29 +04:00
switch ( DIGITAL_NFC_DEP_PFB_TYPE ( pfb ) ) {
case DIGITAL_NFC_DEP_PFB_I_PDU :
if ( DIGITAL_NFC_DEP_PFB_PNI ( pfb ) ! = ddev - > curr_nfc_dep_pni ) {
PROTOCOL_ERR ( " 14.12.3.3 " ) ;
rc = - EIO ;
goto error ;
}
ddev - > curr_nfc_dep_pni =
DIGITAL_NFC_DEP_PFB_PNI ( ddev - > curr_nfc_dep_pni + 1 ) ;
rc = 0 ;
break ;
case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU :
2013-09-20 18:56:40 +04:00
pr_err ( " Received a ACK/NACK PDU \n " ) ;
2013-09-19 19:55:29 +04:00
rc = - EIO ;
goto error ;
case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU :
if ( ! DIGITAL_NFC_DEP_PFB_IS_TIMEOUT ( pfb ) ) {
rc = - EINVAL ;
goto error ;
}
2014-09-24 03:38:03 +04:00
rc = digital_in_send_rtox ( ddev , data_exch , resp - > data [ 0 ] ) ;
2013-09-19 19:55:29 +04:00
if ( rc )
goto error ;
kfree_skb ( resp ) ;
return ;
}
if ( DIGITAL_NFC_DEP_MI_BIT_SET ( pfb ) ) {
2013-09-20 18:56:40 +04:00
pr_err ( " MI bit set. Chained PDU not supported \n " ) ;
2013-09-19 19:55:29 +04:00
rc = - EIO ;
goto error ;
}
exit :
data_exch - > cb ( data_exch - > cb_context , resp , rc ) ;
error :
kfree ( data_exch ) ;
if ( rc )
kfree_skb ( resp ) ;
}
int digital_in_send_dep_req ( struct nfc_digital_dev * ddev ,
struct nfc_target * target , struct sk_buff * skb ,
struct digital_data_exch * data_exch )
{
struct digital_dep_req_res * dep_req ;
skb_push ( skb , sizeof ( struct digital_dep_req_res ) ) ;
dep_req = ( struct digital_dep_req_res * ) skb - > data ;
dep_req - > dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT ;
dep_req - > cmd = DIGITAL_CMD_DEP_REQ ;
dep_req - > pfb = ddev - > curr_nfc_dep_pni ;
digital_skb_push_dep_sod ( ddev , skb ) ;
ddev - > skb_add_crc ( skb ) ;
return digital_in_send_cmd ( ddev , skb , 1500 , digital_in_recv_dep_res ,
data_exch ) ;
}
2013-09-19 19:55:30 +04:00
2014-01-07 02:34:48 +04:00
static void digital_tg_set_rf_tech ( struct nfc_digital_dev * ddev , u8 rf_tech )
{
ddev - > curr_rf_tech = rf_tech ;
ddev - > skb_add_crc = digital_skb_add_crc_none ;
ddev - > skb_check_crc = digital_skb_check_crc_none ;
if ( DIGITAL_DRV_CAPS_TG_CRC ( ddev ) )
return ;
switch ( ddev - > curr_rf_tech ) {
case NFC_DIGITAL_RF_TECH_106A :
ddev - > skb_add_crc = digital_skb_add_crc_a ;
ddev - > skb_check_crc = digital_skb_check_crc_a ;
break ;
case NFC_DIGITAL_RF_TECH_212F :
case NFC_DIGITAL_RF_TECH_424F :
ddev - > skb_add_crc = digital_skb_add_crc_f ;
ddev - > skb_check_crc = digital_skb_check_crc_f ;
break ;
default :
break ;
}
}
2013-09-19 19:55:30 +04:00
static void digital_tg_recv_dep_req ( struct nfc_digital_dev * ddev , void * arg ,
struct sk_buff * resp )
{
int rc ;
struct digital_dep_req_res * dep_req ;
2014-09-24 03:38:03 +04:00
u8 pfb ;
2013-09-19 19:55:30 +04:00
size_t size ;
if ( IS_ERR ( resp ) ) {
rc = PTR_ERR ( resp ) ;
resp = NULL ;
goto exit ;
}
rc = ddev - > skb_check_crc ( resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.6 " ) ;
goto exit ;
}
rc = digital_skb_pull_dep_sod ( ddev , resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.2 " ) ;
goto exit ;
}
size = sizeof ( struct digital_dep_req_res ) ;
dep_req = ( struct digital_dep_req_res * ) resp - > data ;
if ( resp - > len < size | | dep_req - > dir ! = DIGITAL_NFC_DEP_FRAME_DIR_OUT | |
dep_req - > cmd ! = DIGITAL_CMD_DEP_REQ ) {
rc = - EIO ;
goto exit ;
}
2014-09-24 03:38:03 +04:00
pfb = dep_req - > pfb ;
2014-09-24 03:38:05 +04:00
if ( DIGITAL_NFC_DEP_DID_BIT_SET ( pfb ) ) {
if ( ddev - > did & & ( ddev - > did = = resp - > data [ 3 ] ) ) {
size + + ;
} else {
rc = - EIO ;
goto exit ;
}
} else if ( ddev - > did ) {
rc = - EIO ;
goto exit ;
}
2013-09-19 19:55:30 +04:00
2014-09-24 03:38:06 +04:00
if ( DIGITAL_NFC_DEP_NAD_BIT_SET ( pfb ) ) {
rc = - EIO ;
goto exit ;
}
2014-09-24 03:38:03 +04:00
if ( size > resp - > len ) {
2013-09-19 19:55:30 +04:00
rc = - EIO ;
goto exit ;
}
2014-09-24 03:38:03 +04:00
skb_pull ( resp , size ) ;
switch ( DIGITAL_NFC_DEP_PFB_TYPE ( pfb ) ) {
2013-09-19 19:55:30 +04:00
case DIGITAL_NFC_DEP_PFB_I_PDU :
2013-09-20 18:56:40 +04:00
pr_debug ( " DIGITAL_NFC_DEP_PFB_I_PDU \n " ) ;
2014-09-24 03:38:03 +04:00
ddev - > curr_nfc_dep_pni = DIGITAL_NFC_DEP_PFB_PNI ( pfb ) ;
2013-09-19 19:55:30 +04:00
break ;
case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU :
2013-09-20 18:56:40 +04:00
pr_err ( " Received a ACK/NACK PDU \n " ) ;
2013-09-19 19:55:30 +04:00
rc = - EINVAL ;
goto exit ;
case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU :
2013-09-20 18:56:40 +04:00
pr_err ( " Received a SUPERVISOR PDU \n " ) ;
2013-09-19 19:55:30 +04:00
rc = - EINVAL ;
goto exit ;
}
rc = nfc_tm_data_received ( ddev - > nfc_dev , resp ) ;
exit :
if ( rc )
kfree_skb ( resp ) ;
}
int digital_tg_send_dep_res ( struct nfc_digital_dev * ddev , struct sk_buff * skb )
{
struct digital_dep_req_res * dep_res ;
skb_push ( skb , sizeof ( struct digital_dep_req_res ) ) ;
dep_res = ( struct digital_dep_req_res * ) skb - > data ;
dep_res - > dir = DIGITAL_NFC_DEP_FRAME_DIR_IN ;
dep_res - > cmd = DIGITAL_CMD_DEP_RES ;
dep_res - > pfb = ddev - > curr_nfc_dep_pni ;
2014-09-24 03:38:05 +04:00
if ( ddev - > did ) {
dep_res - > pfb | = DIGITAL_NFC_DEP_PFB_DID_BIT ;
memcpy ( skb_put ( skb , sizeof ( ddev - > did ) ) , & ddev - > did ,
sizeof ( ddev - > did ) ) ;
}
2013-09-19 19:55:30 +04:00
digital_skb_push_dep_sod ( ddev , skb ) ;
ddev - > skb_add_crc ( skb ) ;
return digital_tg_send_cmd ( ddev , skb , 1500 , digital_tg_recv_dep_req ,
NULL ) ;
}
static void digital_tg_send_psl_res_complete ( struct nfc_digital_dev * ddev ,
void * arg , struct sk_buff * resp )
{
2014-01-02 14:58:13 +04:00
u8 rf_tech = ( unsigned long ) arg ;
2013-09-19 19:55:30 +04:00
if ( IS_ERR ( resp ) )
return ;
2014-01-07 02:34:48 +04:00
digital_tg_set_rf_tech ( ddev , rf_tech ) ;
2013-09-19 19:55:30 +04:00
digital_tg_configure_hw ( ddev , NFC_DIGITAL_CONFIG_RF_TECH , rf_tech ) ;
digital_tg_listen ( ddev , 1500 , digital_tg_recv_dep_req , NULL ) ;
dev_kfree_skb ( resp ) ;
}
static int digital_tg_send_psl_res ( struct nfc_digital_dev * ddev , u8 did ,
u8 rf_tech )
{
struct digital_psl_res * psl_res ;
struct sk_buff * skb ;
int rc ;
skb = digital_skb_alloc ( ddev , sizeof ( struct digital_psl_res ) ) ;
if ( ! skb )
return - ENOMEM ;
skb_put ( skb , sizeof ( struct digital_psl_res ) ) ;
psl_res = ( struct digital_psl_res * ) skb - > data ;
psl_res - > dir = DIGITAL_NFC_DEP_FRAME_DIR_IN ;
psl_res - > cmd = DIGITAL_CMD_PSL_RES ;
psl_res - > did = did ;
digital_skb_push_dep_sod ( ddev , skb ) ;
ddev - > skb_add_crc ( skb ) ;
rc = digital_tg_send_cmd ( ddev , skb , 0 , digital_tg_send_psl_res_complete ,
2014-01-02 14:58:13 +04:00
( void * ) ( unsigned long ) rf_tech ) ;
2013-09-19 19:55:30 +04:00
if ( rc )
kfree_skb ( skb ) ;
return rc ;
}
static void digital_tg_recv_psl_req ( struct nfc_digital_dev * ddev , void * arg ,
struct sk_buff * resp )
{
int rc ;
struct digital_psl_req * psl_req ;
u8 rf_tech ;
u8 dsi ;
if ( IS_ERR ( resp ) ) {
rc = PTR_ERR ( resp ) ;
resp = NULL ;
goto exit ;
}
rc = ddev - > skb_check_crc ( resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.6 " ) ;
goto exit ;
}
rc = digital_skb_pull_dep_sod ( ddev , resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.2 " ) ;
goto exit ;
}
psl_req = ( struct digital_psl_req * ) resp - > data ;
if ( resp - > len ! = sizeof ( struct digital_psl_req ) | |
psl_req - > dir ! = DIGITAL_NFC_DEP_FRAME_DIR_OUT | |
psl_req - > cmd ! = DIGITAL_CMD_PSL_REQ ) {
rc = - EIO ;
goto exit ;
}
dsi = ( psl_req - > brs > > 3 ) & 0x07 ;
switch ( dsi ) {
case 0 :
rf_tech = NFC_DIGITAL_RF_TECH_106A ;
break ;
case 1 :
rf_tech = NFC_DIGITAL_RF_TECH_212F ;
break ;
case 2 :
rf_tech = NFC_DIGITAL_RF_TECH_424F ;
break ;
default :
2013-12-08 19:22:53 +04:00
pr_err ( " Unsupported dsi value %d \n " , dsi ) ;
2013-09-19 19:55:30 +04:00
goto exit ;
}
rc = digital_tg_send_psl_res ( ddev , psl_req - > did , rf_tech ) ;
exit :
kfree_skb ( resp ) ;
}
static void digital_tg_send_atr_res_complete ( struct nfc_digital_dev * ddev ,
void * arg , struct sk_buff * resp )
{
int offset ;
if ( IS_ERR ( resp ) ) {
digital_poll_next_tech ( ddev ) ;
return ;
}
offset = 2 ;
if ( resp - > data [ 0 ] = = DIGITAL_NFC_DEP_NFCA_SOD_SB )
offset + + ;
if ( resp - > data [ offset ] = = DIGITAL_CMD_PSL_REQ )
digital_tg_recv_psl_req ( ddev , arg , resp ) ;
else
digital_tg_recv_dep_req ( ddev , arg , resp ) ;
}
static int digital_tg_send_atr_res ( struct nfc_digital_dev * ddev ,
struct digital_atr_req * atr_req )
{
struct digital_atr_res * atr_res ;
struct sk_buff * skb ;
u8 * gb ;
size_t gb_len ;
int rc ;
gb = nfc_get_local_general_bytes ( ddev - > nfc_dev , & gb_len ) ;
if ( ! gb )
gb_len = 0 ;
skb = digital_skb_alloc ( ddev , sizeof ( struct digital_atr_res ) + gb_len ) ;
if ( ! skb )
return - ENOMEM ;
skb_put ( skb , sizeof ( struct digital_atr_res ) ) ;
atr_res = ( struct digital_atr_res * ) skb - > data ;
memset ( atr_res , 0 , sizeof ( struct digital_atr_res ) ) ;
atr_res - > dir = DIGITAL_NFC_DEP_FRAME_DIR_IN ;
atr_res - > cmd = DIGITAL_CMD_ATR_RES ;
memcpy ( atr_res - > nfcid3 , atr_req - > nfcid3 , sizeof ( atr_req - > nfcid3 ) ) ;
atr_res - > to = 8 ;
atr_res - > pp = DIGITAL_LR_BITS_PAYLOAD_SIZE_254B ;
if ( gb_len ) {
skb_put ( skb , gb_len ) ;
atr_res - > pp | = DIGITAL_GB_BIT ;
memcpy ( atr_res - > gb , gb , gb_len ) ;
}
digital_skb_push_dep_sod ( ddev , skb ) ;
ddev - > skb_add_crc ( skb ) ;
rc = digital_tg_send_cmd ( ddev , skb , 999 ,
digital_tg_send_atr_res_complete , NULL ) ;
2014-09-24 03:38:02 +04:00
if ( rc )
2013-09-19 19:55:30 +04:00
kfree_skb ( skb ) ;
return rc ;
}
void digital_tg_recv_atr_req ( struct nfc_digital_dev * ddev , void * arg ,
struct sk_buff * resp )
{
int rc ;
struct digital_atr_req * atr_req ;
size_t gb_len , min_size ;
2014-07-02 20:03:49 +04:00
u8 poll_tech_count ;
2013-09-19 19:55:30 +04:00
if ( IS_ERR ( resp ) ) {
rc = PTR_ERR ( resp ) ;
resp = NULL ;
goto exit ;
}
if ( ! resp - > len ) {
rc = - EIO ;
goto exit ;
}
if ( resp - > data [ 0 ] = = DIGITAL_NFC_DEP_NFCA_SOD_SB ) {
min_size = DIGITAL_ATR_REQ_MIN_SIZE + 2 ;
2014-01-07 02:34:48 +04:00
digital_tg_set_rf_tech ( ddev , NFC_DIGITAL_RF_TECH_106A ) ;
2013-09-19 19:55:30 +04:00
} else {
min_size = DIGITAL_ATR_REQ_MIN_SIZE + 1 ;
2014-01-07 02:34:48 +04:00
digital_tg_set_rf_tech ( ddev , NFC_DIGITAL_RF_TECH_212F ) ;
2013-09-19 19:55:30 +04:00
}
if ( resp - > len < min_size ) {
rc = - EIO ;
goto exit ;
}
2014-01-07 02:34:37 +04:00
ddev - > curr_protocol = NFC_PROTO_NFC_DEP_MASK ;
2013-09-19 19:55:30 +04:00
rc = ddev - > skb_check_crc ( resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.6 " ) ;
goto exit ;
}
rc = digital_skb_pull_dep_sod ( ddev , resp ) ;
if ( rc ) {
PROTOCOL_ERR ( " 14.4.1.2 " ) ;
goto exit ;
}
atr_req = ( struct digital_atr_req * ) resp - > data ;
if ( atr_req - > dir ! = DIGITAL_NFC_DEP_FRAME_DIR_OUT | |
2014-09-24 03:38:05 +04:00
atr_req - > cmd ! = DIGITAL_CMD_ATR_REQ | |
atr_req - > did > DIGITAL_DID_MAX ) {
2013-09-19 19:55:30 +04:00
rc = - EINVAL ;
goto exit ;
}
2014-09-24 03:38:05 +04:00
ddev - > did = atr_req - > did ;
2013-09-19 19:55:30 +04:00
rc = digital_tg_configure_hw ( ddev , NFC_DIGITAL_CONFIG_FRAMING ,
NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED ) ;
if ( rc )
goto exit ;
rc = digital_tg_send_atr_res ( ddev , atr_req ) ;
if ( rc )
goto exit ;
gb_len = resp - > len - sizeof ( struct digital_atr_req ) ;
2014-07-02 20:03:49 +04:00
poll_tech_count = ddev - > poll_tech_count ;
ddev - > poll_tech_count = 0 ;
2013-09-19 19:55:30 +04:00
rc = nfc_tm_activated ( ddev - > nfc_dev , NFC_PROTO_NFC_DEP_MASK ,
NFC_COMM_PASSIVE , atr_req - > gb , gb_len ) ;
2014-07-02 20:03:49 +04:00
if ( rc ) {
ddev - > poll_tech_count = poll_tech_count ;
2013-09-19 19:55:30 +04:00
goto exit ;
2014-07-02 20:03:49 +04:00
}
2013-09-19 19:55:30 +04:00
rc = 0 ;
exit :
if ( rc )
digital_poll_next_tech ( ddev ) ;
dev_kfree_skb ( resp ) ;
}