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 ) .
*
* Copyright ( C ) 2011 Texas Instruments , Inc .
2014-10-21 16:52:44 +02:00
* Copyright ( C ) 2014 Marvell International Ltd .
2011-09-18 11:19:35 +03:00
*
* Written by Ilan Elias < ilane @ ti . com >
*
* Acknowledgements :
* This file is based on hci_core . 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
2012-07-12 19:17:34 +02:00
# include <linux/module.h>
2011-09-18 11:19:35 +03:00
# include <linux/types.h>
# include <linux/workqueue.h>
# include <linux/completion.h>
2011-07-15 11:47:34 -04:00
# include <linux/export.h>
2011-09-18 11:19:35 +03:00
# include <linux/sched.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>
static void nci_cmd_work ( struct work_struct * work ) ;
static void nci_rx_work ( struct work_struct * work ) ;
static void nci_tx_work ( struct work_struct * work ) ;
/* ---- NCI requests ---- */
void nci_req_complete ( struct nci_dev * ndev , int result )
{
if ( ndev - > req_status = = NCI_REQ_PEND ) {
ndev - > req_result = result ;
ndev - > req_status = NCI_REQ_DONE ;
complete ( & ndev - > req_completion ) ;
}
}
static void nci_req_cancel ( struct nci_dev * ndev , int err )
{
if ( ndev - > req_status = = NCI_REQ_PEND ) {
ndev - > req_result = err ;
ndev - > req_status = NCI_REQ_CANCELED ;
complete ( & ndev - > req_completion ) ;
}
}
/* Execute request and wait for completion. */
static int __nci_request ( struct nci_dev * ndev ,
2012-03-05 01:03:54 +01:00
void ( * req ) ( struct nci_dev * ndev , unsigned long opt ) ,
unsigned long opt , __u32 timeout )
2011-09-18 11:19:35 +03:00
{
int rc = 0 ;
2011-12-09 09:35:39 +03:00
long completion_rc ;
2011-09-18 11:19:35 +03:00
ndev - > req_status = NCI_REQ_PEND ;
2014-02-13 13:25:48 +08:00
reinit_completion ( & ndev - > req_completion ) ;
2011-09-18 11:19:35 +03:00
req ( ndev , opt ) ;
2012-03-05 01:03:54 +01:00
completion_rc =
wait_for_completion_interruptible_timeout ( & ndev - > req_completion ,
timeout ) ;
2011-09-18 11:19:35 +03:00
2011-11-29 11:37:33 -08:00
pr_debug ( " wait_for_completion return %ld \n " , completion_rc ) ;
2011-09-18 11:19:35 +03:00
if ( completion_rc > 0 ) {
switch ( ndev - > req_status ) {
case NCI_REQ_DONE :
rc = nci_to_errno ( ndev - > req_result ) ;
break ;
case NCI_REQ_CANCELED :
rc = - ndev - > req_result ;
break ;
default :
rc = - ETIMEDOUT ;
break ;
}
} else {
2011-11-29 11:37:32 -08:00
pr_err ( " wait_for_completion_interruptible_timeout failed %ld \n " ,
completion_rc ) ;
2011-09-18 11:19:35 +03:00
rc = ( ( completion_rc = = 0 ) ? ( - ETIMEDOUT ) : ( completion_rc ) ) ;
}
ndev - > req_status = ndev - > req_result = 0 ;
return rc ;
}
static inline int nci_request ( struct nci_dev * ndev ,
2012-03-05 01:03:54 +01:00
void ( * req ) ( struct nci_dev * ndev ,
unsigned long opt ) ,
unsigned long opt , __u32 timeout )
2011-09-18 11:19:35 +03:00
{
int rc ;
if ( ! test_bit ( NCI_UP , & ndev - > flags ) )
return - ENETDOWN ;
/* Serialize all requests */
mutex_lock ( & ndev - > req_lock ) ;
rc = __nci_request ( ndev , req , opt , timeout ) ;
mutex_unlock ( & ndev - > req_lock ) ;
return rc ;
}
static void nci_reset_req ( struct nci_dev * ndev , unsigned long opt )
{
2011-11-09 12:09:14 +02:00
struct nci_core_reset_cmd cmd ;
cmd . reset_type = NCI_RESET_TYPE_RESET_CONFIG ;
nci_send_cmd ( ndev , NCI_OP_CORE_RESET_CMD , 1 , & cmd ) ;
2011-09-18 11:19:35 +03:00
}
static void nci_init_req ( struct nci_dev * ndev , unsigned long opt )
{
nci_send_cmd ( ndev , NCI_OP_CORE_INIT_CMD , 0 , NULL ) ;
}
static void nci_init_complete_req ( struct nci_dev * ndev , unsigned long opt )
{
2011-09-22 10:47:52 +03:00
struct nci_rf_disc_map_cmd cmd ;
struct disc_map_config * cfg = cmd . mapping_configs ;
__u8 * num = & cmd . num_mapping_configs ;
2011-09-18 11:19:35 +03:00
int i ;
/* set rf mapping configurations */
2011-09-22 10:47:52 +03:00
* num = 0 ;
2011-09-18 11:19:35 +03:00
/* by default mapping is set to NCI_RF_INTERFACE_FRAME */
for ( i = 0 ; i < ndev - > num_supported_rf_interfaces ; i + + ) {
if ( ndev - > supported_rf_interfaces [ i ] = =
2012-03-05 01:03:54 +01:00
NCI_RF_INTERFACE_ISO_DEP ) {
2011-09-22 10:47:52 +03:00
cfg [ * num ] . rf_protocol = NCI_RF_PROTOCOL_ISO_DEP ;
2011-12-20 16:57:40 +02:00
cfg [ * num ] . mode = NCI_DISC_MAP_MODE_POLL |
NCI_DISC_MAP_MODE_LISTEN ;
cfg [ * num ] . rf_interface = NCI_RF_INTERFACE_ISO_DEP ;
2011-09-22 10:47:52 +03:00
( * num ) + + ;
2011-09-18 11:19:35 +03:00
} else if ( ndev - > supported_rf_interfaces [ i ] = =
2012-03-05 01:03:54 +01:00
NCI_RF_INTERFACE_NFC_DEP ) {
2011-09-22 10:47:52 +03:00
cfg [ * num ] . rf_protocol = NCI_RF_PROTOCOL_NFC_DEP ;
2011-12-20 16:57:40 +02:00
cfg [ * num ] . mode = NCI_DISC_MAP_MODE_POLL |
NCI_DISC_MAP_MODE_LISTEN ;
cfg [ * num ] . rf_interface = NCI_RF_INTERFACE_NFC_DEP ;
2011-09-22 10:47:52 +03:00
( * num ) + + ;
2011-09-18 11:19:35 +03:00
}
2011-09-22 10:47:52 +03:00
if ( * num = = NCI_MAX_NUM_MAPPING_CONFIGS )
2011-09-18 11:19:35 +03:00
break ;
}
nci_send_cmd ( ndev , NCI_OP_RF_DISCOVER_MAP_CMD ,
2012-03-05 01:03:54 +01:00
( 1 + ( ( * num ) * sizeof ( struct disc_map_config ) ) ) , & cmd ) ;
2011-09-18 11:19:35 +03:00
}
2012-08-15 11:46:22 +03:00
struct nci_set_config_param {
__u8 id ;
size_t len ;
__u8 * val ;
} ;
static void nci_set_config_req ( struct nci_dev * ndev , unsigned long opt )
{
struct nci_set_config_param * param = ( struct nci_set_config_param * ) opt ;
struct nci_core_set_config_cmd cmd ;
BUG_ON ( param - > len > NCI_MAX_PARAM_LEN ) ;
cmd . num_params = 1 ;
cmd . param . id = param - > id ;
cmd . param . len = param - > len ;
memcpy ( cmd . param . val , param - > val , param - > len ) ;
nci_send_cmd ( ndev , NCI_OP_CORE_SET_CONFIG_CMD , ( 3 + param - > len ) , & cmd ) ;
}
2014-10-21 16:52:44 +02:00
struct nci_rf_discover_param {
__u32 im_protocols ;
__u32 tm_protocols ;
} ;
2011-09-18 11:19:35 +03:00
static void nci_rf_discover_req ( struct nci_dev * ndev , unsigned long opt )
{
2014-10-21 16:52:44 +02:00
struct nci_rf_discover_param * param =
( struct nci_rf_discover_param * ) opt ;
2011-09-18 11:19:35 +03:00
struct nci_rf_disc_cmd cmd ;
cmd . num_disc_configs = 0 ;
if ( ( cmd . num_disc_configs < NCI_MAX_NUM_RF_CONFIGS ) & &
2014-10-21 16:52:44 +02:00
( param - > im_protocols & NFC_PROTO_JEWEL_MASK | |
param - > im_protocols & NFC_PROTO_MIFARE_MASK | |
param - > im_protocols & NFC_PROTO_ISO14443_MASK | |
param - > im_protocols & NFC_PROTO_NFC_DEP_MASK ) ) {
2011-12-20 16:57:40 +02:00
cmd . disc_configs [ cmd . num_disc_configs ] . rf_tech_and_mode =
2012-03-05 01:03:54 +01:00
NCI_NFC_A_PASSIVE_POLL_MODE ;
2011-09-18 11:19:35 +03:00
cmd . disc_configs [ cmd . num_disc_configs ] . frequency = 1 ;
cmd . num_disc_configs + + ;
}
if ( ( cmd . num_disc_configs < NCI_MAX_NUM_RF_CONFIGS ) & &
2014-10-21 16:52:44 +02:00
( param - > im_protocols & NFC_PROTO_ISO14443_B_MASK ) ) {
2011-12-20 16:57:40 +02:00
cmd . disc_configs [ cmd . num_disc_configs ] . rf_tech_and_mode =
2012-03-05 01:03:54 +01:00
NCI_NFC_B_PASSIVE_POLL_MODE ;
2011-09-18 11:19:35 +03:00
cmd . disc_configs [ cmd . num_disc_configs ] . frequency = 1 ;
cmd . num_disc_configs + + ;
}
if ( ( cmd . num_disc_configs < NCI_MAX_NUM_RF_CONFIGS ) & &
2014-10-21 16:52:44 +02:00
( param - > im_protocols & NFC_PROTO_FELICA_MASK | |
param - > im_protocols & NFC_PROTO_NFC_DEP_MASK ) ) {
2011-12-20 16:57:40 +02:00
cmd . disc_configs [ cmd . num_disc_configs ] . rf_tech_and_mode =
2012-03-05 01:03:54 +01:00
NCI_NFC_F_PASSIVE_POLL_MODE ;
2011-09-18 11:19:35 +03:00
cmd . disc_configs [ cmd . num_disc_configs ] . frequency = 1 ;
cmd . num_disc_configs + + ;
}
2014-07-22 19:48:38 +02:00
if ( ( cmd . num_disc_configs < NCI_MAX_NUM_RF_CONFIGS ) & &
2014-10-21 16:52:44 +02:00
( param - > im_protocols & NFC_PROTO_ISO15693_MASK ) ) {
2014-07-22 19:48:38 +02:00
cmd . disc_configs [ cmd . num_disc_configs ] . rf_tech_and_mode =
NCI_NFC_V_PASSIVE_POLL_MODE ;
cmd . disc_configs [ cmd . num_disc_configs ] . frequency = 1 ;
cmd . num_disc_configs + + ;
}
2014-10-21 16:52:44 +02:00
if ( ( cmd . num_disc_configs < NCI_MAX_NUM_RF_CONFIGS - 1 ) & &
( param - > tm_protocols & NFC_PROTO_NFC_DEP_MASK ) ) {
cmd . disc_configs [ cmd . num_disc_configs ] . rf_tech_and_mode =
NCI_NFC_A_PASSIVE_LISTEN_MODE ;
cmd . disc_configs [ cmd . num_disc_configs ] . frequency = 1 ;
cmd . num_disc_configs + + ;
cmd . disc_configs [ cmd . num_disc_configs ] . rf_tech_and_mode =
NCI_NFC_F_PASSIVE_LISTEN_MODE ;
cmd . disc_configs [ cmd . num_disc_configs ] . frequency = 1 ;
cmd . num_disc_configs + + ;
}
2011-09-18 11:19:35 +03:00
nci_send_cmd ( ndev , NCI_OP_RF_DISCOVER_CMD ,
2012-03-05 01:03:54 +01:00
( 1 + ( cmd . num_disc_configs * sizeof ( struct disc_config ) ) ) ,
& cmd ) ;
2011-09-18 11:19:35 +03:00
}
2012-01-18 13:16:14 +02:00
struct nci_rf_discover_select_param {
__u8 rf_discovery_id ;
__u8 rf_protocol ;
} ;
static void nci_rf_discover_select_req ( struct nci_dev * ndev , unsigned long opt )
{
struct nci_rf_discover_select_param * param =
2012-03-05 01:03:54 +01:00
( struct nci_rf_discover_select_param * ) opt ;
2012-01-18 13:16:14 +02:00
struct nci_rf_discover_select_cmd cmd ;
cmd . rf_discovery_id = param - > rf_discovery_id ;
cmd . rf_protocol = param - > rf_protocol ;
switch ( cmd . rf_protocol ) {
case NCI_RF_PROTOCOL_ISO_DEP :
cmd . rf_interface = NCI_RF_INTERFACE_ISO_DEP ;
break ;
case NCI_RF_PROTOCOL_NFC_DEP :
cmd . rf_interface = NCI_RF_INTERFACE_NFC_DEP ;
break ;
default :
cmd . rf_interface = NCI_RF_INTERFACE_FRAME ;
break ;
}
nci_send_cmd ( ndev , NCI_OP_RF_DISCOVER_SELECT_CMD ,
2012-03-05 01:03:54 +01:00
sizeof ( struct nci_rf_discover_select_cmd ) , & cmd ) ;
2012-01-18 13:16:14 +02:00
}
2011-09-18 11:19:35 +03:00
static void nci_rf_deactivate_req ( struct nci_dev * ndev , unsigned long opt )
{
struct nci_rf_deactivate_cmd cmd ;
cmd . type = NCI_DEACTIVATE_TYPE_IDLE_MODE ;
nci_send_cmd ( ndev , NCI_OP_RF_DEACTIVATE_CMD ,
2012-03-05 01:03:54 +01:00
sizeof ( struct nci_rf_deactivate_cmd ) , & cmd ) ;
2011-09-18 11:19:35 +03:00
}
static int nci_open_device ( struct nci_dev * ndev )
{
int rc = 0 ;
mutex_lock ( & ndev - > req_lock ) ;
if ( test_bit ( NCI_UP , & ndev - > flags ) ) {
rc = - EALREADY ;
goto done ;
}
if ( ndev - > ops - > open ( ndev ) ) {
rc = - EIO ;
goto done ;
}
atomic_set ( & ndev - > cmd_cnt , 1 ) ;
set_bit ( NCI_INIT , & ndev - > flags ) ;
rc = __nci_request ( ndev , nci_reset_req , 0 ,
2012-03-05 01:03:54 +01:00
msecs_to_jiffies ( NCI_RESET_TIMEOUT ) ) ;
2011-09-18 11:19:35 +03:00
2014-02-06 11:28:31 -08:00
if ( ndev - > ops - > setup )
2014-01-06 12:58:17 -08:00
ndev - > ops - > setup ( ndev ) ;
2011-09-18 11:19:35 +03:00
if ( ! rc ) {
rc = __nci_request ( ndev , nci_init_req , 0 ,
2012-03-05 01:03:54 +01:00
msecs_to_jiffies ( NCI_INIT_TIMEOUT ) ) ;
2011-09-18 11:19:35 +03:00
}
if ( ! rc ) {
rc = __nci_request ( ndev , nci_init_complete_req , 0 ,
2012-03-05 01:03:54 +01:00
msecs_to_jiffies ( NCI_INIT_TIMEOUT ) ) ;
2011-09-18 11:19:35 +03:00
}
clear_bit ( NCI_INIT , & ndev - > flags ) ;
if ( ! rc ) {
set_bit ( NCI_UP , & ndev - > flags ) ;
2012-01-18 13:16:14 +02:00
nci_clear_target_list ( ndev ) ;
2012-01-18 13:16:12 +02:00
atomic_set ( & ndev - > state , NCI_IDLE ) ;
2011-09-18 11:19:35 +03:00
} else {
/* Init failed, cleanup */
skb_queue_purge ( & ndev - > cmd_q ) ;
skb_queue_purge ( & ndev - > rx_q ) ;
skb_queue_purge ( & ndev - > tx_q ) ;
ndev - > ops - > close ( ndev ) ;
ndev - > flags = 0 ;
}
done :
mutex_unlock ( & ndev - > req_lock ) ;
return rc ;
}
static int nci_close_device ( struct nci_dev * ndev )
{
nci_req_cancel ( ndev , ENODEV ) ;
mutex_lock ( & ndev - > req_lock ) ;
if ( ! test_and_clear_bit ( NCI_UP , & ndev - > flags ) ) {
del_timer_sync ( & ndev - > cmd_timer ) ;
2012-01-17 12:03:50 +02:00
del_timer_sync ( & ndev - > data_timer ) ;
2011-09-18 11:19:35 +03:00
mutex_unlock ( & ndev - > req_lock ) ;
return 0 ;
}
/* Drop RX and TX queues */
skb_queue_purge ( & ndev - > rx_q ) ;
skb_queue_purge ( & ndev - > tx_q ) ;
/* Flush RX and TX wq */
flush_workqueue ( ndev - > rx_wq ) ;
flush_workqueue ( ndev - > tx_wq ) ;
/* Reset device */
skb_queue_purge ( & ndev - > cmd_q ) ;
atomic_set ( & ndev - > cmd_cnt , 1 ) ;
set_bit ( NCI_INIT , & ndev - > flags ) ;
__nci_request ( ndev , nci_reset_req , 0 ,
2012-03-05 01:03:54 +01:00
msecs_to_jiffies ( NCI_RESET_TIMEOUT ) ) ;
2011-09-18 11:19:35 +03:00
clear_bit ( NCI_INIT , & ndev - > flags ) ;
2013-12-23 14:15:13 -08:00
del_timer_sync ( & ndev - > cmd_timer ) ;
2011-09-18 11:19:35 +03:00
/* Flush cmd wq */
flush_workqueue ( ndev - > cmd_wq ) ;
/* After this point our queues are empty
* and no works are scheduled . */
ndev - > ops - > close ( ndev ) ;
/* Clear flags */
ndev - > flags = 0 ;
mutex_unlock ( & ndev - > req_lock ) ;
return 0 ;
}
/* NCI command timer function */
static void nci_cmd_timer ( unsigned long arg )
{
struct nci_dev * ndev = ( void * ) arg ;
atomic_set ( & ndev - > cmd_cnt , 1 ) ;
queue_work ( ndev - > cmd_wq , & ndev - > cmd_work ) ;
}
2012-01-17 12:03:50 +02:00
/* NCI data exchange timer function */
static void nci_data_timer ( unsigned long arg )
{
struct nci_dev * ndev = ( void * ) arg ;
set_bit ( NCI_DATA_EXCHANGE_TO , & ndev - > flags ) ;
queue_work ( ndev - > rx_wq , & ndev - > rx_work ) ;
}
2011-09-18 11:19:35 +03:00
static int nci_dev_up ( struct nfc_dev * nfc_dev )
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
return nci_open_device ( ndev ) ;
}
static int nci_dev_down ( struct nfc_dev * nfc_dev )
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
return nci_close_device ( ndev ) ;
}
2014-01-06 12:58:18 -08:00
int nci_set_config ( struct nci_dev * ndev , __u8 id , size_t len , __u8 * val )
{
struct nci_set_config_param param ;
if ( ! val | | ! len )
return 0 ;
param . id = id ;
param . len = len ;
param . val = val ;
return __nci_request ( ndev , nci_set_config_req , ( unsigned long ) & param ,
msecs_to_jiffies ( NCI_SET_CONFIG_TIMEOUT ) ) ;
}
EXPORT_SYMBOL ( nci_set_config ) ;
2012-08-15 11:46:22 +03:00
static int nci_set_local_general_bytes ( struct nfc_dev * nfc_dev )
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
struct nci_set_config_param param ;
2014-10-21 16:52:47 +02:00
int rc ;
2012-08-15 11:46:22 +03:00
param . val = nfc_get_local_general_bytes ( nfc_dev , & param . len ) ;
if ( ( param . val = = NULL ) | | ( param . len = = 0 ) )
2012-10-04 15:15:46 +02:00
return 0 ;
2012-08-15 11:46:22 +03:00
2012-10-04 15:15:45 +02:00
if ( param . len > NFC_MAX_GT_LEN )
2012-08-15 11:46:22 +03:00
return - EINVAL ;
param . id = NCI_PN_ATR_REQ_GEN_BYTES ;
2014-10-21 16:52:47 +02:00
rc = nci_request ( ndev , nci_set_config_req , ( unsigned long ) & param ,
msecs_to_jiffies ( NCI_SET_CONFIG_TIMEOUT ) ) ;
if ( rc )
return rc ;
param . id = NCI_LN_ATR_RES_GEN_BYTES ;
2012-10-04 15:15:46 +02:00
return nci_request ( ndev , nci_set_config_req , ( unsigned long ) & param ,
msecs_to_jiffies ( NCI_SET_CONFIG_TIMEOUT ) ) ;
2012-08-15 11:46:22 +03:00
}
2014-10-21 16:52:45 +02:00
static int nci_set_listen_parameters ( struct nfc_dev * nfc_dev )
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
int rc ;
__u8 val ;
val = NCI_LA_SEL_INFO_NFC_DEP_MASK ;
rc = nci_set_config ( ndev , NCI_LA_SEL_INFO , 1 , & val ) ;
if ( rc )
return rc ;
val = NCI_LF_PROTOCOL_TYPE_NFC_DEP_MASK ;
rc = nci_set_config ( ndev , NCI_LF_PROTOCOL_TYPE , 1 , & val ) ;
if ( rc )
return rc ;
val = NCI_LF_CON_BITR_F_212 | NCI_LF_CON_BITR_F_424 ;
return nci_set_config ( ndev , NCI_LF_CON_BITR_F , 1 , & val ) ;
}
2012-05-15 15:57:06 +02:00
static int nci_start_poll ( struct nfc_dev * nfc_dev ,
__u32 im_protocols , __u32 tm_protocols )
2011-09-18 11:19:35 +03:00
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
2014-10-21 16:52:44 +02:00
struct nci_rf_discover_param param ;
2011-09-18 11:19:35 +03:00
int rc ;
2012-01-18 13:16:14 +02:00
if ( ( atomic_read ( & ndev - > state ) = = NCI_DISCOVERY ) | |
2012-03-05 01:03:54 +01:00
( atomic_read ( & ndev - > state ) = = NCI_W4_ALL_DISCOVERIES ) ) {
2011-11-29 11:37:32 -08:00
pr_err ( " unable to start poll, since poll is already active \n " ) ;
2011-09-18 11:19:35 +03:00
return - EBUSY ;
}
2011-09-22 11:13:01 +03:00
if ( ndev - > target_active_prot ) {
2011-11-29 11:37:32 -08:00
pr_err ( " there is an active target \n " ) ;
2011-09-22 11:13:01 +03:00
return - EBUSY ;
}
2012-01-18 13:16:14 +02:00
if ( ( atomic_read ( & ndev - > state ) = = NCI_W4_HOST_SELECT ) | |
2012-03-05 01:03:54 +01:00
( atomic_read ( & ndev - > state ) = = NCI_POLL_ACTIVE ) ) {
2012-01-18 13:16:14 +02:00
pr_debug ( " target active or w4 select, implicitly deactivate \n " ) ;
2011-09-18 11:19:35 +03:00
rc = nci_request ( ndev , nci_rf_deactivate_req , 0 ,
2012-03-05 01:03:54 +01:00
msecs_to_jiffies ( NCI_RF_DEACTIVATE_TIMEOUT ) ) ;
2011-09-18 11:19:35 +03:00
if ( rc )
return - EBUSY ;
}
2014-10-21 16:52:47 +02:00
if ( ( im_protocols | tm_protocols ) & NFC_PROTO_NFC_DEP_MASK ) {
2012-08-15 11:46:22 +03:00
rc = nci_set_local_general_bytes ( nfc_dev ) ;
if ( rc ) {
pr_err ( " failed to set local general bytes \n " ) ;
return rc ;
}
}
2014-10-21 16:52:45 +02:00
if ( tm_protocols & NFC_PROTO_NFC_DEP_MASK ) {
rc = nci_set_listen_parameters ( nfc_dev ) ;
if ( rc )
pr_err ( " failed to set listen parameters \n " ) ;
}
2014-10-21 16:52:44 +02:00
param . im_protocols = im_protocols ;
param . tm_protocols = tm_protocols ;
rc = nci_request ( ndev , nci_rf_discover_req , ( unsigned long ) & param ,
2012-03-05 01:03:54 +01:00
msecs_to_jiffies ( NCI_RF_DISC_TIMEOUT ) ) ;
2011-09-18 11:19:35 +03:00
if ( ! rc )
2012-05-15 15:57:06 +02:00
ndev - > poll_prots = im_protocols ;
2011-09-18 11:19:35 +03:00
return rc ;
}
static void nci_stop_poll ( struct nfc_dev * nfc_dev )
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
2012-01-18 13:16:14 +02:00
if ( ( atomic_read ( & ndev - > state ) ! = NCI_DISCOVERY ) & &
2012-03-05 01:03:54 +01:00
( atomic_read ( & ndev - > state ) ! = NCI_W4_ALL_DISCOVERIES ) ) {
2011-11-29 11:37:32 -08:00
pr_err ( " unable to stop poll, since poll is not active \n " ) ;
2011-09-18 11:19:35 +03:00
return ;
}
nci_request ( ndev , nci_rf_deactivate_req , 0 ,
2012-03-05 01:03:54 +01:00
msecs_to_jiffies ( NCI_RF_DEACTIVATE_TIMEOUT ) ) ;
2011-09-18 11:19:35 +03:00
}
2012-05-07 12:31:13 +02:00
static int nci_activate_target ( struct nfc_dev * nfc_dev ,
struct nfc_target * target , __u32 protocol )
2011-09-18 11:19:35 +03:00
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
2012-01-18 13:16:14 +02:00
struct nci_rf_discover_select_param param ;
2012-05-07 12:31:13 +02:00
struct nfc_target * nci_target = NULL ;
2012-01-18 13:16:14 +02:00
int i ;
int rc = 0 ;
2011-09-18 11:19:35 +03:00
2012-05-07 12:31:13 +02:00
pr_debug ( " target_idx %d, protocol 0x%x \n " , target - > idx , protocol ) ;
2011-09-18 11:19:35 +03:00
2012-01-18 13:16:14 +02:00
if ( ( atomic_read ( & ndev - > state ) ! = NCI_W4_HOST_SELECT ) & &
2012-03-05 01:03:54 +01:00
( atomic_read ( & ndev - > state ) ! = NCI_POLL_ACTIVE ) ) {
2011-11-29 11:37:32 -08:00
pr_err ( " there is no available target to activate \n " ) ;
2011-09-18 11:19:35 +03:00
return - EINVAL ;
}
if ( ndev - > target_active_prot ) {
2011-11-29 11:37:32 -08:00
pr_err ( " there is already an active target \n " ) ;
2011-09-18 11:19:35 +03:00
return - EBUSY ;
}
2012-01-18 13:16:14 +02:00
for ( i = 0 ; i < ndev - > n_targets ; i + + ) {
2012-05-07 12:31:13 +02:00
if ( ndev - > targets [ i ] . idx = = target - > idx ) {
nci_target = & ndev - > targets [ i ] ;
2012-01-18 13:16:14 +02:00
break ;
}
}
2012-05-07 12:31:13 +02:00
if ( ! nci_target ) {
2012-01-18 13:16:14 +02:00
pr_err ( " unable to find the selected target \n " ) ;
return - EINVAL ;
}
2012-05-07 12:31:13 +02:00
if ( ! ( nci_target - > supported_protocols & ( 1 < < protocol ) ) ) {
2011-11-29 11:37:32 -08:00
pr_err ( " target does not support the requested protocol 0x%x \n " ,
protocol ) ;
2011-09-18 11:19:35 +03:00
return - EINVAL ;
}
2012-01-18 13:16:14 +02:00
if ( atomic_read ( & ndev - > state ) = = NCI_W4_HOST_SELECT ) {
2012-05-07 12:31:13 +02:00
param . rf_discovery_id = nci_target - > logical_idx ;
2012-01-18 13:16:14 +02:00
if ( protocol = = NFC_PROTO_JEWEL )
param . rf_protocol = NCI_RF_PROTOCOL_T1T ;
else if ( protocol = = NFC_PROTO_MIFARE )
param . rf_protocol = NCI_RF_PROTOCOL_T2T ;
else if ( protocol = = NFC_PROTO_FELICA )
param . rf_protocol = NCI_RF_PROTOCOL_T3T ;
2012-07-04 00:14:04 +02:00
else if ( protocol = = NFC_PROTO_ISO14443 | |
protocol = = NFC_PROTO_ISO14443_B )
2012-01-18 13:16:14 +02:00
param . rf_protocol = NCI_RF_PROTOCOL_ISO_DEP ;
else
param . rf_protocol = NCI_RF_PROTOCOL_NFC_DEP ;
rc = nci_request ( ndev , nci_rf_discover_select_req ,
2012-03-05 01:03:54 +01:00
( unsigned long ) & param ,
msecs_to_jiffies ( NCI_RF_DISC_SELECT_TIMEOUT ) ) ;
2012-01-18 13:16:14 +02:00
}
2011-09-18 11:19:35 +03:00
2012-01-18 13:16:14 +02:00
if ( ! rc )
ndev - > target_active_prot = protocol ;
return rc ;
2011-09-18 11:19:35 +03:00
}
2012-05-07 12:31:13 +02:00
static void nci_deactivate_target ( struct nfc_dev * nfc_dev ,
struct nfc_target * target )
2011-09-18 11:19:35 +03:00
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
2012-08-15 11:46:24 +03:00
pr_debug ( " entry \n " ) ;
2011-09-18 11:19:35 +03:00
if ( ! ndev - > target_active_prot ) {
2011-11-29 11:37:32 -08:00
pr_err ( " unable to deactivate target, no active target \n " ) ;
2011-09-18 11:19:35 +03:00
return ;
}
ndev - > target_active_prot = 0 ;
2012-01-18 13:16:12 +02:00
if ( atomic_read ( & ndev - > state ) = = NCI_POLL_ACTIVE ) {
2011-09-18 11:19:35 +03:00
nci_request ( ndev , nci_rf_deactivate_req , 0 ,
2012-03-05 01:03:54 +01:00
msecs_to_jiffies ( NCI_RF_DEACTIVATE_TIMEOUT ) ) ;
2011-09-18 11:19:35 +03:00
}
}
2012-08-15 11:46:24 +03:00
static int nci_dep_link_up ( struct nfc_dev * nfc_dev , struct nfc_target * target ,
__u8 comm_mode , __u8 * gb , size_t gb_len )
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
int rc ;
pr_debug ( " target_idx %d, comm_mode %d \n " , target - > idx , comm_mode ) ;
rc = nci_activate_target ( nfc_dev , target , NFC_PROTO_NFC_DEP ) ;
if ( rc )
return rc ;
rc = nfc_set_remote_general_bytes ( nfc_dev , ndev - > remote_gb ,
ndev - > remote_gb_len ) ;
if ( ! rc )
rc = nfc_dep_link_is_up ( nfc_dev , target - > idx , NFC_COMM_PASSIVE ,
NFC_RF_INITIATOR ) ;
return rc ;
}
static int nci_dep_link_down ( struct nfc_dev * nfc_dev )
{
pr_debug ( " entry \n " ) ;
nci_deactivate_target ( nfc_dev , NULL ) ;
return 0 ;
}
2012-05-16 15:55:48 +02:00
static int nci_transceive ( struct nfc_dev * nfc_dev , struct nfc_target * target ,
struct sk_buff * skb ,
data_exchange_cb_t cb , void * cb_context )
2011-09-18 11:19:35 +03:00
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
2011-09-22 11:36:19 +03:00
int rc ;
2011-09-18 11:19:35 +03:00
2012-05-07 12:31:13 +02:00
pr_debug ( " target_idx %d, len %d \n " , target - > idx , skb - > len ) ;
2011-09-18 11:19:35 +03:00
if ( ! ndev - > target_active_prot ) {
2011-11-29 11:37:32 -08:00
pr_err ( " unable to exchange data, no active target \n " ) ;
2011-09-18 11:19:35 +03:00
return - EINVAL ;
}
2011-09-22 11:36:19 +03:00
if ( test_and_set_bit ( NCI_DATA_EXCHANGE , & ndev - > flags ) )
return - EBUSY ;
2011-09-18 11:19:35 +03:00
/* store cb and context to be used on receiving data */
ndev - > data_exchange_cb = cb ;
ndev - > data_exchange_cb_context = cb_context ;
2011-11-09 12:09:14 +02:00
rc = nci_send_data ( ndev , NCI_STATIC_RF_CONN_ID , skb ) ;
2011-09-22 11:36:19 +03:00
if ( rc )
clear_bit ( NCI_DATA_EXCHANGE , & ndev - > flags ) ;
return rc ;
2011-09-18 11:19:35 +03:00
}
2014-10-21 16:52:48 +02:00
static int nci_tm_send ( struct nfc_dev * nfc_dev , struct sk_buff * skb )
{
struct nci_dev * ndev = nfc_get_drvdata ( nfc_dev ) ;
int rc ;
rc = nci_send_data ( ndev , NCI_STATIC_RF_CONN_ID , skb ) ;
if ( rc )
pr_err ( " unable to send data \n " ) ;
return rc ;
}
2013-05-10 11:57:06 +02:00
static int nci_enable_se ( struct nfc_dev * nfc_dev , u32 se_idx )
{
return 0 ;
}
static int nci_disable_se ( struct nfc_dev * nfc_dev , u32 se_idx )
{
return 0 ;
}
static int nci_discover_se ( struct nfc_dev * nfc_dev )
{
return 0 ;
}
2011-09-18 11:19:35 +03:00
static struct nfc_ops nci_nfc_ops = {
. dev_up = nci_dev_up ,
. dev_down = nci_dev_down ,
. start_poll = nci_start_poll ,
. stop_poll = nci_stop_poll ,
2012-08-15 11:46:24 +03:00
. dep_link_up = nci_dep_link_up ,
. dep_link_down = nci_dep_link_down ,
2011-09-18 11:19:35 +03:00
. activate_target = nci_activate_target ,
. deactivate_target = nci_deactivate_target ,
2012-05-16 15:55:48 +02:00
. im_transceive = nci_transceive ,
2014-10-21 16:52:48 +02:00
. tm_send = nci_tm_send ,
2013-05-10 11:57:06 +02:00
. enable_se = nci_enable_se ,
. disable_se = nci_disable_se ,
. discover_se = nci_discover_se ,
2011-09-18 11:19:35 +03:00
} ;
/* ---- Interface to NCI drivers ---- */
/**
* nci_allocate_device - allocate a new nci device
*
* @ ops : device operations
* @ supported_protocols : NFC protocols supported by the device
*/
struct nci_dev * nci_allocate_device ( struct nci_ops * ops ,
2012-03-05 01:03:54 +01:00
__u32 supported_protocols ,
int tx_headroom , int tx_tailroom )
2011-09-18 11:19:35 +03:00
{
2011-09-23 09:14:35 +03:00
struct nci_dev * ndev ;
2011-09-18 11:19:35 +03:00
2011-11-29 11:37:35 -08:00
pr_debug ( " supported_protocols 0x%x \n " , supported_protocols ) ;
2011-09-18 11:19:35 +03:00
if ( ! ops - > open | | ! ops - > close | | ! ops - > send )
2011-09-23 09:14:35 +03:00
return NULL ;
2011-09-18 11:19:35 +03:00
if ( ! supported_protocols )
2011-09-23 09:14:35 +03:00
return NULL ;
2011-09-18 11:19:35 +03:00
ndev = kzalloc ( sizeof ( struct nci_dev ) , GFP_KERNEL ) ;
if ( ! ndev )
2011-09-23 09:14:35 +03:00
return NULL ;
2011-09-18 11:19:35 +03:00
ndev - > ops = ops ;
ndev - > tx_headroom = tx_headroom ;
ndev - > tx_tailroom = tx_tailroom ;
2014-02-13 13:25:48 +08:00
init_completion ( & ndev - > req_completion ) ;
2011-09-18 11:19:35 +03:00
ndev - > nfc_dev = nfc_allocate_device ( & nci_nfc_ops ,
2012-03-05 01:03:54 +01:00
supported_protocols ,
tx_headroom + NCI_DATA_HDR_SIZE ,
tx_tailroom ) ;
2011-09-18 11:19:35 +03:00
if ( ! ndev - > nfc_dev )
goto free_exit ;
nfc_set_drvdata ( ndev - > nfc_dev , ndev ) ;
2011-09-23 09:14:35 +03:00
return ndev ;
2011-09-18 11:19:35 +03:00
free_exit :
kfree ( ndev ) ;
2011-09-23 09:14:35 +03:00
return NULL ;
2011-09-18 11:19:35 +03:00
}
EXPORT_SYMBOL ( nci_allocate_device ) ;
/**
* nci_free_device - deallocate nci device
*
* @ ndev : The nci device to deallocate
*/
void nci_free_device ( struct nci_dev * ndev )
{
nfc_free_device ( ndev - > nfc_dev ) ;
kfree ( ndev ) ;
}
EXPORT_SYMBOL ( nci_free_device ) ;
/**
* nci_register_device - register a nci device in the nfc subsystem
*
* @ dev : The nci device to register
*/
int nci_register_device ( struct nci_dev * ndev )
{
int rc ;
struct device * dev = & ndev - > nfc_dev - > dev ;
char name [ 32 ] ;
ndev - > flags = 0 ;
INIT_WORK ( & ndev - > cmd_work , nci_cmd_work ) ;
snprintf ( name , sizeof ( name ) , " %s_nci_cmd_wq " , dev_name ( dev ) ) ;
ndev - > cmd_wq = create_singlethread_workqueue ( name ) ;
if ( ! ndev - > cmd_wq ) {
rc = - ENOMEM ;
2014-07-22 19:48:39 +02:00
goto exit ;
2011-09-18 11:19:35 +03:00
}
INIT_WORK ( & ndev - > rx_work , nci_rx_work ) ;
snprintf ( name , sizeof ( name ) , " %s_nci_rx_wq " , dev_name ( dev ) ) ;
ndev - > rx_wq = create_singlethread_workqueue ( name ) ;
if ( ! ndev - > rx_wq ) {
rc = - ENOMEM ;
goto destroy_cmd_wq_exit ;
}
INIT_WORK ( & ndev - > tx_work , nci_tx_work ) ;
snprintf ( name , sizeof ( name ) , " %s_nci_tx_wq " , dev_name ( dev ) ) ;
ndev - > tx_wq = create_singlethread_workqueue ( name ) ;
if ( ! ndev - > tx_wq ) {
rc = - ENOMEM ;
goto destroy_rx_wq_exit ;
}
skb_queue_head_init ( & ndev - > cmd_q ) ;
skb_queue_head_init ( & ndev - > rx_q ) ;
skb_queue_head_init ( & ndev - > tx_q ) ;
setup_timer ( & ndev - > cmd_timer , nci_cmd_timer ,
2012-03-05 01:03:54 +01:00
( unsigned long ) ndev ) ;
2012-01-17 12:03:50 +02:00
setup_timer ( & ndev - > data_timer , nci_data_timer ,
2012-03-05 01:03:54 +01:00
( unsigned long ) ndev ) ;
2011-09-18 11:19:35 +03:00
mutex_init ( & ndev - > req_lock ) ;
2014-07-22 19:48:39 +02:00
rc = nfc_register_device ( ndev - > nfc_dev ) ;
if ( rc )
goto destroy_rx_wq_exit ;
2011-09-18 11:19:35 +03:00
goto exit ;
destroy_rx_wq_exit :
destroy_workqueue ( ndev - > rx_wq ) ;
destroy_cmd_wq_exit :
destroy_workqueue ( ndev - > cmd_wq ) ;
exit :
return rc ;
}
EXPORT_SYMBOL ( nci_register_device ) ;
/**
* nci_unregister_device - unregister a nci device in the nfc subsystem
*
* @ dev : The nci device to unregister
*/
void nci_unregister_device ( struct nci_dev * ndev )
{
nci_close_device ( ndev ) ;
destroy_workqueue ( ndev - > cmd_wq ) ;
destroy_workqueue ( ndev - > rx_wq ) ;
destroy_workqueue ( ndev - > tx_wq ) ;
nfc_unregister_device ( ndev - > nfc_dev ) ;
}
EXPORT_SYMBOL ( nci_unregister_device ) ;
/**
* nci_recv_frame - receive frame from NCI drivers
*
2013-05-22 11:36:17 +02:00
* @ ndev : The nci device
2011-09-18 11:19:35 +03:00
* @ skb : The sk_buff to receive
*/
2013-05-22 11:36:17 +02:00
int nci_recv_frame ( struct nci_dev * ndev , struct sk_buff * skb )
2011-09-18 11:19:35 +03:00
{
2011-11-29 11:37:35 -08:00
pr_debug ( " len %d \n " , skb - > len ) ;
2011-09-18 11:19:35 +03:00
2012-10-04 15:15:51 +02:00
if ( ! ndev | | ( ! test_bit ( NCI_UP , & ndev - > flags ) & &
! test_bit ( NCI_INIT , & ndev - > flags ) ) ) {
2011-09-18 11:19:35 +03:00
kfree_skb ( skb ) ;
return - ENXIO ;
}
/* Queue frame for rx worker thread */
skb_queue_tail ( & ndev - > rx_q , skb ) ;
queue_work ( ndev - > rx_wq , & ndev - > rx_work ) ;
return 0 ;
}
EXPORT_SYMBOL ( nci_recv_frame ) ;
2013-05-22 11:36:17 +02:00
static int nci_send_frame ( struct nci_dev * ndev , struct sk_buff * skb )
2011-09-18 11:19:35 +03:00
{
2011-11-29 11:37:35 -08:00
pr_debug ( " len %d \n " , skb - > len ) ;
2011-09-18 11:19:35 +03:00
if ( ! ndev ) {
kfree_skb ( skb ) ;
return - ENODEV ;
}
/* Get rid of skb owner, prior to sending to the driver. */
skb_orphan ( skb ) ;
2014-05-05 19:52:27 +09:00
/* Send copy to sniffer */
nfc_send_to_raw_sock ( ndev - > nfc_dev , skb ,
RAW_PAYLOAD_NCI , NFC_DIRECTION_TX ) ;
2013-05-22 11:36:17 +02:00
return ndev - > ops - > send ( ndev , skb ) ;
2011-09-18 11:19:35 +03:00
}
/* Send NCI command */
int nci_send_cmd ( struct nci_dev * ndev , __u16 opcode , __u8 plen , void * payload )
{
struct nci_ctrl_hdr * hdr ;
struct sk_buff * skb ;
2011-11-29 11:37:35 -08:00
pr_debug ( " opcode 0x%x, plen %d \n " , opcode , plen ) ;
2011-09-18 11:19:35 +03:00
skb = nci_skb_alloc ( ndev , ( NCI_CTRL_HDR_SIZE + plen ) , GFP_KERNEL ) ;
if ( ! skb ) {
2011-11-29 11:37:32 -08:00
pr_err ( " no memory for command \n " ) ;
2011-09-18 11:19:35 +03:00
return - ENOMEM ;
}
hdr = ( struct nci_ctrl_hdr * ) skb_put ( skb , NCI_CTRL_HDR_SIZE ) ;
hdr - > gid = nci_opcode_gid ( opcode ) ;
hdr - > oid = nci_opcode_oid ( opcode ) ;
hdr - > plen = plen ;
nci_mt_set ( ( __u8 * ) hdr , NCI_MT_CMD_PKT ) ;
nci_pbf_set ( ( __u8 * ) hdr , NCI_PBF_LAST ) ;
if ( plen )
memcpy ( skb_put ( skb , plen ) , payload , plen ) ;
skb_queue_tail ( & ndev - > cmd_q , skb ) ;
queue_work ( ndev - > cmd_wq , & ndev - > cmd_work ) ;
return 0 ;
}
/* ---- NCI TX Data worker thread ---- */
static void nci_tx_work ( struct work_struct * work )
{
struct nci_dev * ndev = container_of ( work , struct nci_dev , tx_work ) ;
struct sk_buff * skb ;
2011-11-29 11:37:35 -08:00
pr_debug ( " credits_cnt %d \n " , atomic_read ( & ndev - > credits_cnt ) ) ;
2011-09-18 11:19:35 +03:00
/* Send queued tx data */
while ( atomic_read ( & ndev - > credits_cnt ) ) {
skb = skb_dequeue ( & ndev - > tx_q ) ;
if ( ! skb )
return ;
2011-11-09 12:09:16 +02:00
/* Check if data flow control is used */
if ( atomic_read ( & ndev - > credits_cnt ) ! =
2012-03-05 01:03:54 +01:00
NCI_DATA_FLOW_CONTROL_NOT_USED )
2011-11-09 12:09:16 +02:00
atomic_dec ( & ndev - > credits_cnt ) ;
2011-09-18 11:19:35 +03:00
2011-11-29 11:37:33 -08:00
pr_debug ( " NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d \n " ,
nci_pbf ( skb - > data ) ,
nci_conn_id ( skb - > data ) ,
nci_plen ( skb - > data ) ) ;
2011-09-18 11:19:35 +03:00
2013-05-22 11:36:17 +02:00
nci_send_frame ( ndev , skb ) ;
2012-01-17 12:03:50 +02:00
mod_timer ( & ndev - > data_timer ,
2012-03-05 01:03:54 +01:00
jiffies + msecs_to_jiffies ( NCI_DATA_TIMEOUT ) ) ;
2011-09-18 11:19:35 +03:00
}
}
/* ----- NCI RX worker thread (data & control) ----- */
static void nci_rx_work ( struct work_struct * work )
{
struct nci_dev * ndev = container_of ( work , struct nci_dev , rx_work ) ;
struct sk_buff * skb ;
while ( ( skb = skb_dequeue ( & ndev - > rx_q ) ) ) {
2014-05-05 19:52:27 +09:00
/* Send copy to sniffer */
nfc_send_to_raw_sock ( ndev - > nfc_dev , skb ,
RAW_PAYLOAD_NCI , NFC_DIRECTION_RX ) ;
2011-09-18 11:19:35 +03:00
/* Process frame */
switch ( nci_mt ( skb - > data ) ) {
case NCI_MT_RSP_PKT :
nci_rsp_packet ( ndev , skb ) ;
break ;
case NCI_MT_NTF_PKT :
nci_ntf_packet ( ndev , skb ) ;
break ;
case NCI_MT_DATA_PKT :
nci_rx_data_packet ( ndev , skb ) ;
break ;
default :
2011-11-29 11:37:32 -08:00
pr_err ( " unknown MT 0x%x \n " , nci_mt ( skb - > data ) ) ;
2011-09-18 11:19:35 +03:00
kfree_skb ( skb ) ;
break ;
}
}
2012-01-17 12:03:50 +02:00
/* check if a data exchange timout has occurred */
if ( test_bit ( NCI_DATA_EXCHANGE_TO , & ndev - > flags ) ) {
/* complete the data exchange transaction, if exists */
if ( test_bit ( NCI_DATA_EXCHANGE , & ndev - > flags ) )
nci_data_exchange_complete ( ndev , NULL , - ETIMEDOUT ) ;
clear_bit ( NCI_DATA_EXCHANGE_TO , & ndev - > flags ) ;
}
2011-09-18 11:19:35 +03:00
}
/* ----- NCI TX CMD worker thread ----- */
static void nci_cmd_work ( struct work_struct * work )
{
struct nci_dev * ndev = container_of ( work , struct nci_dev , cmd_work ) ;
struct sk_buff * skb ;
2011-11-29 11:37:35 -08:00
pr_debug ( " cmd_cnt %d \n " , atomic_read ( & ndev - > cmd_cnt ) ) ;
2011-09-18 11:19:35 +03:00
/* Send queued command */
if ( atomic_read ( & ndev - > cmd_cnt ) ) {
skb = skb_dequeue ( & ndev - > cmd_q ) ;
if ( ! skb )
return ;
atomic_dec ( & ndev - > cmd_cnt ) ;
2011-11-29 11:37:33 -08:00
pr_debug ( " NCI TX: MT=cmd, PBF=%d, GID=0x%x, OID=0x%x, plen=%d \n " ,
nci_pbf ( skb - > data ) ,
nci_opcode_gid ( nci_opcode ( skb - > data ) ) ,
nci_opcode_oid ( nci_opcode ( skb - > data ) ) ,
nci_plen ( skb - > data ) ) ;
2011-09-18 11:19:35 +03:00
2013-05-22 11:36:17 +02:00
nci_send_frame ( ndev , skb ) ;
2011-09-18 11:19:35 +03:00
mod_timer ( & ndev - > cmd_timer ,
2012-03-05 01:03:54 +01:00
jiffies + msecs_to_jiffies ( NCI_CMD_TIMEOUT ) ) ;
2011-09-18 11:19:35 +03:00
}
}
2012-07-12 19:17:34 +02:00
MODULE_LICENSE ( " GPL " ) ;