2011-07-02 02:31:33 +04:00
/*
* Copyright ( C ) 2011 Instituto Nokia de Tecnologia
*
* Authors :
* Lauro Ramos Venancio < lauro . venancio @ openbossa . org >
* Aloisio Almeida Jr < aloisio . almeida @ openbossa . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 20:56:16 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2011-07-02 02:31:33 +04:00
*/
2011-12-14 19:43:05 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
2011-11-29 23:37:32 +04:00
2011-07-02 02:31:33 +04:00
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/slab.h>
2013-04-11 13:52:20 +04:00
# include <linux/rfkill.h>
2011-12-14 19:43:06 +04:00
# include <linux/nfc.h>
2011-07-02 02:31:33 +04:00
2012-06-12 18:54:16 +04:00
# include <net/genetlink.h>
2011-07-02 02:31:33 +04:00
# include "nfc.h"
# define VERSION "0.1"
2012-04-10 21:43:12 +04:00
# define NFC_CHECK_PRES_FREQ_MS 2000
2011-07-02 02:31:33 +04:00
int nfc_devlist_generation ;
DEFINE_MUTEX ( nfc_devlist_mutex ) ;
2012-10-22 17:57:58 +04:00
/* NFC device ID bitmap */
static DEFINE_IDA ( nfc_index_ida ) ;
2013-07-31 03:19:43 +04:00
int nfc_fw_download ( struct nfc_dev * dev , const char * firmware_name )
2013-04-29 19:13:27 +04:00
{
int rc = 0 ;
pr_debug ( " %s do firmware %s \n " , dev_name ( & dev - > dev ) , firmware_name ) ;
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
if ( dev - > dev_up ) {
rc = - EBUSY ;
goto error ;
}
2013-07-31 03:19:43 +04:00
if ( ! dev - > ops - > fw_download ) {
2013-04-29 19:13:27 +04:00
rc = - EOPNOTSUPP ;
goto error ;
}
2013-07-31 03:19:43 +04:00
dev - > fw_download_in_progress = true ;
rc = dev - > ops - > fw_download ( dev , firmware_name ) ;
2013-04-29 19:13:27 +04:00
if ( rc )
2013-07-31 03:19:43 +04:00
dev - > fw_download_in_progress = false ;
2013-04-29 19:13:27 +04:00
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
2013-07-19 16:57:55 +04:00
/**
* nfc_fw_download_done - inform that a firmware download was completed
*
* @ dev : The nfc device to which firmware was downloaded
* @ firmware_name : The firmware filename
* @ result : The positive value of a standard errno value
*/
int nfc_fw_download_done ( struct nfc_dev * dev , const char * firmware_name ,
u32 result )
2013-04-29 19:13:27 +04:00
{
2013-07-31 03:19:43 +04:00
dev - > fw_download_in_progress = false ;
2013-04-29 19:13:27 +04:00
2013-07-19 16:57:55 +04:00
return nfc_genl_fw_download_done ( dev , firmware_name , result ) ;
2013-04-29 19:13:27 +04:00
}
2013-07-31 03:19:43 +04:00
EXPORT_SYMBOL ( nfc_fw_download_done ) ;
2013-04-29 19:13:27 +04:00
2011-09-18 12:19:33 +04:00
/**
* nfc_dev_up - turn on the NFC device
*
* @ dev : The nfc device to be turned on
*
* The device remains up until the nfc_dev_down function is called .
*/
int nfc_dev_up ( struct nfc_dev * dev )
{
int rc = 0 ;
2011-11-29 23:37:33 +04:00
pr_debug ( " dev_name=%s \n " , dev_name ( & dev - > dev ) ) ;
2011-09-18 12:19:33 +04:00
device_lock ( & dev - > dev ) ;
2013-04-11 13:52:20 +04:00
if ( dev - > rfkill & & rfkill_blocked ( dev - > rfkill ) ) {
rc = - ERFKILL ;
goto error ;
}
2011-09-18 12:19:33 +04:00
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
2013-07-31 03:19:43 +04:00
if ( dev - > fw_download_in_progress ) {
2013-04-29 19:13:27 +04:00
rc = - EBUSY ;
goto error ;
}
2011-09-18 12:19:33 +04:00
if ( dev - > dev_up ) {
rc = - EALREADY ;
goto error ;
}
if ( dev - > ops - > dev_up )
rc = dev - > ops - > dev_up ( dev ) ;
if ( ! rc )
dev - > dev_up = true ;
2013-05-10 13:57:06 +04:00
/* We have to enable the device before discovering SEs */
2013-12-22 04:00:20 +04:00
if ( dev - > ops - > discover_se & & dev - > ops - > discover_se ( dev ) )
pr_err ( " SE discovery failed \n " ) ;
2013-05-10 13:57:06 +04:00
2011-09-18 12:19:33 +04:00
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
/**
* nfc_dev_down - turn off the NFC device
*
* @ dev : The nfc device to be turned off
*/
int nfc_dev_down ( struct nfc_dev * dev )
{
int rc = 0 ;
2011-11-29 23:37:33 +04:00
pr_debug ( " dev_name=%s \n " , dev_name ( & dev - > dev ) ) ;
2011-09-18 12:19:33 +04:00
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
if ( ! dev - > dev_up ) {
rc = - EALREADY ;
goto error ;
}
2012-05-07 14:31:13 +04:00
if ( dev - > polling | | dev - > active_target ) {
2011-09-18 12:19:33 +04:00
rc = - EBUSY ;
goto error ;
}
if ( dev - > ops - > dev_down )
dev - > ops - > dev_down ( dev ) ;
dev - > dev_up = false ;
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
2013-04-11 13:52:20 +04:00
static int nfc_rfkill_set_block ( void * data , bool blocked )
{
struct nfc_dev * dev = data ;
pr_debug ( " %s blocked %d " , dev_name ( & dev - > dev ) , blocked ) ;
if ( ! blocked )
return 0 ;
nfc_dev_down ( dev ) ;
return 0 ;
}
static const struct rfkill_ops nfc_rfkill_ops = {
. set_block = nfc_rfkill_set_block ,
} ;
2011-07-02 02:31:33 +04:00
/**
* nfc_start_poll - start polling for nfc targets
*
* @ dev : The nfc device that must start polling
* @ protocols : bitset of nfc protocols that must be used for polling
*
* The device remains polling for targets until a target is found or
* the nfc_stop_poll function is called .
*/
2012-05-15 17:57:06 +04:00
int nfc_start_poll ( struct nfc_dev * dev , u32 im_protocols , u32 tm_protocols )
2011-07-02 02:31:33 +04:00
{
int rc ;
2012-05-15 17:57:06 +04:00
pr_debug ( " dev_name %s initiator protocols 0x%x target protocols 0x%x \n " ,
dev_name ( & dev - > dev ) , im_protocols , tm_protocols ) ;
2011-07-02 02:31:33 +04:00
2012-05-15 17:57:06 +04:00
if ( ! im_protocols & & ! tm_protocols )
2011-07-02 02:31:33 +04:00
return - EINVAL ;
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
2013-04-10 14:25:30 +04:00
if ( ! dev - > dev_up ) {
rc = - ENODEV ;
goto error ;
}
2011-07-02 02:31:33 +04:00
if ( dev - > polling ) {
rc = - EBUSY ;
goto error ;
}
2012-05-15 17:57:06 +04:00
rc = dev - > ops - > start_poll ( dev , im_protocols , tm_protocols ) ;
2012-05-31 02:02:26 +04:00
if ( ! rc ) {
2011-07-02 02:31:33 +04:00
dev - > polling = true ;
2012-05-31 02:02:26 +04:00
dev - > rf_mode = NFC_RF_NONE ;
}
2011-07-02 02:31:33 +04:00
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
/**
* nfc_stop_poll - stop polling for nfc targets
*
* @ dev : The nfc device that must stop polling
*/
int nfc_stop_poll ( struct nfc_dev * dev )
{
int rc = 0 ;
2011-11-29 23:37:33 +04:00
pr_debug ( " dev_name=%s \n " , dev_name ( & dev - > dev ) ) ;
2011-07-02 02:31:33 +04:00
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
if ( ! dev - > polling ) {
rc = - EINVAL ;
goto error ;
}
dev - > ops - > stop_poll ( dev ) ;
dev - > polling = false ;
2012-10-05 13:05:45 +04:00
dev - > rf_mode = NFC_RF_NONE ;
2011-07-02 02:31:33 +04:00
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
2012-05-07 14:31:13 +04:00
static struct nfc_target * nfc_find_target ( struct nfc_dev * dev , u32 target_idx )
{
int i ;
2012-10-17 17:23:39 +04:00
for ( i = 0 ; i < dev - > n_targets ; i + + ) {
2012-05-07 14:31:13 +04:00
if ( dev - > targets [ i ] . idx = = target_idx )
return & dev - > targets [ i ] ;
}
return NULL ;
}
2012-03-05 04:03:50 +04:00
int nfc_dep_link_up ( struct nfc_dev * dev , int target_index , u8 comm_mode )
2011-12-14 19:43:09 +04:00
{
int rc = 0 ;
2012-03-05 04:03:50 +04:00
u8 * gb ;
size_t gb_len ;
2012-05-07 14:31:13 +04:00
struct nfc_target * target ;
2011-12-14 19:43:09 +04:00
2012-03-05 04:03:50 +04:00
pr_debug ( " dev_name=%s comm %d \n " , dev_name ( & dev - > dev ) , comm_mode ) ;
2011-12-14 19:43:09 +04:00
if ( ! dev - > ops - > dep_link_up )
return - EOPNOTSUPP ;
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
if ( dev - > dep_link_up = = true ) {
rc = - EALREADY ;
goto error ;
}
2012-03-05 04:03:50 +04:00
gb = nfc_llcp_general_bytes ( dev , & gb_len ) ;
if ( gb_len > NFC_MAX_GT_LEN ) {
rc = - EINVAL ;
goto error ;
}
2012-05-07 14:31:13 +04:00
target = nfc_find_target ( dev , target_index ) ;
if ( target = = NULL ) {
rc = - ENOTCONN ;
goto error ;
}
rc = dev - > ops - > dep_link_up ( dev , target , comm_mode , gb , gb_len ) ;
2012-05-31 02:02:26 +04:00
if ( ! rc ) {
2012-05-07 14:31:13 +04:00
dev - > active_target = target ;
2012-05-31 02:02:26 +04:00
dev - > rf_mode = NFC_RF_INITIATOR ;
}
2011-12-14 19:43:09 +04:00
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
int nfc_dep_link_down ( struct nfc_dev * dev )
{
int rc = 0 ;
pr_debug ( " dev_name=%s \n " , dev_name ( & dev - > dev ) ) ;
if ( ! dev - > ops - > dep_link_down )
return - EOPNOTSUPP ;
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
if ( dev - > dep_link_up = = false ) {
rc = - EALREADY ;
goto error ;
}
rc = dev - > ops - > dep_link_down ( dev ) ;
if ( ! rc ) {
dev - > dep_link_up = false ;
2012-05-07 14:31:13 +04:00
dev - > active_target = NULL ;
2012-10-05 13:05:45 +04:00
dev - > rf_mode = NFC_RF_NONE ;
2011-12-14 19:43:12 +04:00
nfc_llcp_mac_is_down ( dev ) ;
2011-12-14 19:43:09 +04:00
nfc_genl_dep_link_down_event ( dev ) ;
}
error :
device_unlock ( & dev - > dev ) ;
2012-10-05 13:05:45 +04:00
2011-12-14 19:43:09 +04:00
return rc ;
}
int nfc_dep_link_is_up ( struct nfc_dev * dev , u32 target_idx ,
2012-03-05 04:03:53 +04:00
u8 comm_mode , u8 rf_mode )
2011-12-14 19:43:09 +04:00
{
dev - > dep_link_up = true ;
2013-11-14 13:03:41 +04:00
if ( ! dev - > active_target & & rf_mode = = NFC_RF_INITIATOR ) {
2013-08-21 16:46:20 +04:00
struct nfc_target * target ;
target = nfc_find_target ( dev , target_idx ) ;
if ( target = = NULL )
return - ENOTCONN ;
dev - > active_target = target ;
}
dev - > polling = false ;
dev - > rf_mode = rf_mode ;
2011-12-14 19:43:12 +04:00
nfc_llcp_mac_is_up ( dev , target_idx , comm_mode , rf_mode ) ;
2011-12-14 19:43:09 +04:00
return nfc_genl_dep_link_up_event ( dev , target_idx , comm_mode , rf_mode ) ;
}
EXPORT_SYMBOL ( nfc_dep_link_is_up ) ;
2011-07-02 02:31:33 +04:00
/**
* nfc_activate_target - prepare the target for data exchange
*
* @ dev : The nfc device that found the target
* @ target_idx : index of the target that must be activated
* @ protocol : nfc protocol that will be used for data exchange
*/
int nfc_activate_target ( struct nfc_dev * dev , u32 target_idx , u32 protocol )
{
int rc ;
2012-05-07 14:31:13 +04:00
struct nfc_target * target ;
2011-07-02 02:31:33 +04:00
2011-11-29 23:37:33 +04:00
pr_debug ( " dev_name=%s target_idx=%u protocol=%u \n " ,
dev_name ( & dev - > dev ) , target_idx , protocol ) ;
2011-07-02 02:31:33 +04:00
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
2012-05-07 14:31:13 +04:00
if ( dev - > active_target ) {
rc = - EBUSY ;
goto error ;
}
target = nfc_find_target ( dev , target_idx ) ;
if ( target = = NULL ) {
rc = - ENOTCONN ;
goto error ;
}
rc = dev - > ops - > activate_target ( dev , target , protocol ) ;
2012-04-10 21:43:12 +04:00
if ( ! rc ) {
2012-05-07 14:31:13 +04:00
dev - > active_target = target ;
2012-05-31 02:02:26 +04:00
dev - > rf_mode = NFC_RF_INITIATOR ;
2011-07-02 02:31:33 +04:00
2012-11-26 21:06:27 +04:00
if ( dev - > ops - > check_presence & & ! dev - > shutting_down )
2012-04-10 21:43:12 +04:00
mod_timer ( & dev - > check_pres_timer , jiffies +
msecs_to_jiffies ( NFC_CHECK_PRES_FREQ_MS ) ) ;
}
2011-07-02 02:31:33 +04:00
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
/**
* nfc_deactivate_target - deactivate a nfc target
*
* @ dev : The nfc device that found the target
* @ target_idx : index of the target that must be deactivated
*/
2015-10-26 00:54:43 +03:00
int nfc_deactivate_target ( struct nfc_dev * dev , u32 target_idx , u8 mode )
2011-07-02 02:31:33 +04:00
{
int rc = 0 ;
2011-11-29 23:37:33 +04:00
pr_debug ( " dev_name=%s target_idx=%u \n " ,
dev_name ( & dev - > dev ) , target_idx ) ;
2011-07-02 02:31:33 +04:00
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
2012-05-07 14:31:13 +04:00
if ( dev - > active_target = = NULL ) {
rc = - ENOTCONN ;
goto error ;
}
if ( dev - > active_target - > idx ! = target_idx ) {
rc = - ENOTCONN ;
goto error ;
}
2012-04-10 21:43:12 +04:00
if ( dev - > ops - > check_presence )
del_timer_sync ( & dev - > check_pres_timer ) ;
2015-10-26 00:54:43 +03:00
dev - > ops - > deactivate_target ( dev , dev - > active_target , mode ) ;
2012-05-07 14:31:13 +04:00
dev - > active_target = NULL ;
2011-07-02 02:31:33 +04:00
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
/**
* nfc_data_exchange - transceive data
*
* @ dev : The nfc device that found the target
* @ target_idx : index of the target
* @ skb : data to be sent
* @ cb : callback called when the response is received
* @ cb_context : parameter for the callback function
*
* The user must wait for the callback before calling this function again .
*/
2012-03-05 04:03:53 +04:00
int nfc_data_exchange ( struct nfc_dev * dev , u32 target_idx , struct sk_buff * skb ,
data_exchange_cb_t cb , void * cb_context )
2011-07-02 02:31:33 +04:00
{
int rc ;
2011-11-29 23:37:33 +04:00
pr_debug ( " dev_name=%s target_idx=%u skb->len=%u \n " ,
dev_name ( & dev - > dev ) , target_idx , skb - > len ) ;
2011-07-02 02:31:33 +04:00
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
kfree_skb ( skb ) ;
goto error ;
}
2012-05-16 17:55:48 +04:00
if ( dev - > rf_mode = = NFC_RF_INITIATOR & & dev - > active_target ! = NULL ) {
if ( dev - > active_target - > idx ! = target_idx ) {
rc = - EADDRNOTAVAIL ;
kfree_skb ( skb ) ;
goto error ;
}
2012-04-10 21:43:11 +04:00
2012-05-16 17:55:48 +04:00
if ( dev - > ops - > check_presence )
del_timer_sync ( & dev - > check_pres_timer ) ;
rc = dev - > ops - > im_transceive ( dev , dev - > active_target , skb , cb ,
cb_context ) ;
2012-11-26 21:06:27 +04:00
if ( ! rc & & dev - > ops - > check_presence & & ! dev - > shutting_down )
2012-05-16 17:55:48 +04:00
mod_timer ( & dev - > check_pres_timer , jiffies +
msecs_to_jiffies ( NFC_CHECK_PRES_FREQ_MS ) ) ;
} else if ( dev - > rf_mode = = NFC_RF_TARGET & & dev - > ops - > tm_send ! = NULL ) {
rc = dev - > ops - > tm_send ( dev , skb ) ;
} else {
rc = - ENOTCONN ;
2012-04-10 21:43:11 +04:00
kfree_skb ( skb ) ;
goto error ;
}
2012-04-10 21:43:12 +04:00
2011-07-02 02:31:33 +04:00
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
2013-08-23 12:02:08 +04:00
struct nfc_se * nfc_find_se ( struct nfc_dev * dev , u32 se_idx )
2013-05-10 18:15:32 +04:00
{
2014-02-14 15:29:19 +04:00
struct nfc_se * se ;
2013-05-10 18:15:32 +04:00
2014-02-14 15:29:19 +04:00
list_for_each_entry ( se , & dev - > secure_elements , list )
2013-05-10 18:15:32 +04:00
if ( se - > idx = = se_idx )
return se ;
return NULL ;
}
2013-08-23 12:02:08 +04:00
EXPORT_SYMBOL ( nfc_find_se ) ;
2013-05-10 18:15:32 +04:00
int nfc_enable_se ( struct nfc_dev * dev , u32 se_idx )
{
struct nfc_se * se ;
int rc ;
pr_debug ( " %s se index %d \n " , dev_name ( & dev - > dev ) , se_idx ) ;
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
if ( ! dev - > dev_up ) {
rc = - ENODEV ;
goto error ;
}
if ( dev - > polling ) {
rc = - EBUSY ;
goto error ;
}
if ( ! dev - > ops - > enable_se | | ! dev - > ops - > disable_se ) {
rc = - EOPNOTSUPP ;
goto error ;
}
2013-08-23 12:02:08 +04:00
se = nfc_find_se ( dev , se_idx ) ;
2013-05-10 18:15:32 +04:00
if ( ! se ) {
rc = - EINVAL ;
goto error ;
}
2013-07-30 16:35:35 +04:00
if ( se - > state = = NFC_SE_ENABLED ) {
2013-05-10 18:15:32 +04:00
rc = - EALREADY ;
goto error ;
}
rc = dev - > ops - > enable_se ( dev , se_idx ) ;
2013-07-30 16:40:05 +04:00
if ( rc > = 0 )
se - > state = NFC_SE_ENABLED ;
2013-05-10 18:15:32 +04:00
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
int nfc_disable_se ( struct nfc_dev * dev , u32 se_idx )
{
struct nfc_se * se ;
int rc ;
pr_debug ( " %s se index %d \n " , dev_name ( & dev - > dev ) , se_idx ) ;
device_lock ( & dev - > dev ) ;
if ( ! device_is_registered ( & dev - > dev ) ) {
rc = - ENODEV ;
goto error ;
}
if ( ! dev - > dev_up ) {
rc = - ENODEV ;
goto error ;
}
if ( ! dev - > ops - > enable_se | | ! dev - > ops - > disable_se ) {
rc = - EOPNOTSUPP ;
goto error ;
}
2013-08-23 12:02:08 +04:00
se = nfc_find_se ( dev , se_idx ) ;
2013-05-10 18:15:32 +04:00
if ( ! se ) {
rc = - EINVAL ;
goto error ;
}
2013-07-30 16:35:35 +04:00
if ( se - > state = = NFC_SE_DISABLED ) {
2013-05-10 18:15:32 +04:00
rc = - EALREADY ;
goto error ;
}
rc = dev - > ops - > disable_se ( dev , se_idx ) ;
2013-07-30 16:40:05 +04:00
if ( rc > = 0 )
se - > state = NFC_SE_DISABLED ;
2013-05-10 18:15:32 +04:00
error :
device_unlock ( & dev - > dev ) ;
return rc ;
}
2011-12-14 19:43:10 +04:00
int nfc_set_remote_general_bytes ( struct nfc_dev * dev , u8 * gb , u8 gb_len )
{
2012-03-05 04:03:53 +04:00
pr_debug ( " dev_name=%s gb_len=%d \n " , dev_name ( & dev - > dev ) , gb_len ) ;
2011-12-14 19:43:10 +04:00
2011-12-14 19:43:12 +04:00
return nfc_llcp_set_remote_gb ( dev , gb , gb_len ) ;
2011-12-14 19:43:10 +04:00
}
EXPORT_SYMBOL ( nfc_set_remote_general_bytes ) ;
2012-04-10 14:51:52 +04:00
u8 * nfc_get_local_general_bytes ( struct nfc_dev * dev , size_t * gb_len )
{
pr_debug ( " dev_name=%s \n " , dev_name ( & dev - > dev ) ) ;
return nfc_llcp_general_bytes ( dev , gb_len ) ;
}
EXPORT_SYMBOL ( nfc_get_local_general_bytes ) ;
2012-05-31 02:05:50 +04:00
int nfc_tm_data_received ( struct nfc_dev * dev , struct sk_buff * skb )
{
/* Only LLCP target mode for now */
if ( dev - > dep_link_up = = false ) {
kfree_skb ( skb ) ;
return - ENOLINK ;
}
return nfc_llcp_data_received ( dev , skb ) ;
}
EXPORT_SYMBOL ( nfc_tm_data_received ) ;
2012-06-01 15:21:13 +04:00
int nfc_tm_activated ( struct nfc_dev * dev , u32 protocol , u8 comm_mode ,
u8 * gb , size_t gb_len )
{
int rc ;
device_lock ( & dev - > dev ) ;
dev - > polling = false ;
if ( gb ! = NULL ) {
rc = nfc_set_remote_general_bytes ( dev , gb , gb_len ) ;
if ( rc < 0 )
goto out ;
}
2012-05-31 02:02:26 +04:00
dev - > rf_mode = NFC_RF_TARGET ;
2012-06-01 15:21:13 +04:00
if ( protocol = = NFC_PROTO_NFC_DEP_MASK )
nfc_dep_link_is_up ( dev , 0 , comm_mode , NFC_RF_TARGET ) ;
rc = nfc_genl_tm_activated ( dev , protocol ) ;
out :
device_unlock ( & dev - > dev ) ;
return rc ;
}
EXPORT_SYMBOL ( nfc_tm_activated ) ;
int nfc_tm_deactivated ( struct nfc_dev * dev )
{
dev - > dep_link_up = false ;
2012-10-05 13:05:45 +04:00
dev - > rf_mode = NFC_RF_NONE ;
2012-06-01 15:21:13 +04:00
return nfc_genl_tm_deactivated ( dev ) ;
}
EXPORT_SYMBOL ( nfc_tm_deactivated ) ;
2011-07-02 02:31:33 +04:00
/**
2011-12-14 19:43:06 +04:00
* nfc_alloc_send_skb - allocate a skb for data exchange responses
2011-07-02 02:31:33 +04:00
*
* @ size : size to allocate
* @ gfp : gfp flags
*/
2011-12-14 19:43:06 +04:00
struct sk_buff * nfc_alloc_send_skb ( struct nfc_dev * dev , struct sock * sk ,
2012-03-05 04:03:53 +04:00
unsigned int flags , unsigned int size ,
unsigned int * err )
2011-12-14 19:43:06 +04:00
{
struct sk_buff * skb ;
unsigned int total_size ;
total_size = size +
dev - > tx_headroom + dev - > tx_tailroom + NFC_HEADER_SIZE ;
skb = sock_alloc_send_skb ( sk , total_size , flags & MSG_DONTWAIT , err ) ;
if ( skb )
skb_reserve ( skb , dev - > tx_headroom + NFC_HEADER_SIZE ) ;
return skb ;
}
/**
* nfc_alloc_recv_skb - allocate a skb for data exchange responses
*
* @ size : size to allocate
* @ gfp : gfp flags
*/
struct sk_buff * nfc_alloc_recv_skb ( unsigned int size , gfp_t gfp )
2011-07-02 02:31:33 +04:00
{
struct sk_buff * skb ;
unsigned int total_size ;
total_size = size + 1 ;
skb = alloc_skb ( total_size , gfp ) ;
if ( skb )
skb_reserve ( skb , 1 ) ;
return skb ;
}
2011-12-14 19:43:06 +04:00
EXPORT_SYMBOL ( nfc_alloc_recv_skb ) ;
2011-07-02 02:31:33 +04:00
2011-07-02 02:31:34 +04:00
/**
* nfc_targets_found - inform that targets were found
*
* @ dev : The nfc device that found the targets
* @ targets : array of nfc targets found
* @ ntargets : targets array size
*
* The device driver must call this function when one or many nfc targets
* are found . After calling this function , the device driver must stop
* polling for targets .
2012-05-03 18:33:32 +04:00
* NOTE : This function can be called with targets = NULL and n_targets = 0 to
* notify a driver error , meaning that the polling operation cannot complete .
2012-05-07 14:31:15 +04:00
* IMPORTANT : this function must not be called from an atomic context .
* In addition , it must also not be called from a context that would prevent
* the NFC Core to call other nfc ops entry point concurrently .
2011-07-02 02:31:34 +04:00
*/
2012-03-05 04:03:53 +04:00
int nfc_targets_found ( struct nfc_dev * dev ,
struct nfc_target * targets , int n_targets )
2011-07-02 02:31:34 +04:00
{
2012-04-10 21:43:09 +04:00
int i ;
2011-11-29 23:37:33 +04:00
pr_debug ( " dev_name=%s n_targets=%d \n " , dev_name ( & dev - > dev ) , n_targets ) ;
2011-07-02 02:31:34 +04:00
2012-04-10 21:43:09 +04:00
for ( i = 0 ; i < n_targets ; i + + )
2012-04-10 21:43:10 +04:00
targets [ i ] . idx = dev - > target_next_idx + + ;
2012-04-10 21:43:09 +04:00
2012-05-07 14:31:15 +04:00
device_lock ( & dev - > dev ) ;
2011-07-02 02:31:34 +04:00
2012-05-03 18:21:58 +04:00
if ( dev - > polling = = false ) {
device_unlock ( & dev - > dev ) ;
return 0 ;
}
dev - > polling = false ;
2011-07-02 02:31:34 +04:00
dev - > targets_generation + + ;
kfree ( dev - > targets ) ;
2012-05-03 18:33:32 +04:00
dev - > targets = NULL ;
2011-07-02 02:31:34 +04:00
2012-05-03 18:33:32 +04:00
if ( targets ) {
dev - > targets = kmemdup ( targets ,
n_targets * sizeof ( struct nfc_target ) ,
GFP_ATOMIC ) ;
if ( ! dev - > targets ) {
dev - > n_targets = 0 ;
device_unlock ( & dev - > dev ) ;
return - ENOMEM ;
}
2011-07-02 02:31:34 +04:00
}
dev - > n_targets = n_targets ;
2012-05-07 14:31:15 +04:00
device_unlock ( & dev - > dev ) ;
2011-07-02 02:31:34 +04:00
nfc_genl_targets_found ( dev ) ;
return 0 ;
}
EXPORT_SYMBOL ( nfc_targets_found ) ;
2012-05-07 14:31:15 +04:00
/**
* nfc_target_lost - inform that an activated target went out of field
*
* @ dev : The nfc device that had the activated target in field
* @ target_idx : the nfc index of the target
*
* The device driver must call this function when the activated target
* goes out of the field .
* IMPORTANT : this function must not be called from an atomic context .
* In addition , it must also not be called from a context that would prevent
* the NFC Core to call other nfc ops entry point concurrently .
*/
2012-04-10 21:43:05 +04:00
int nfc_target_lost ( struct nfc_dev * dev , u32 target_idx )
{
struct nfc_target * tg ;
int i ;
pr_debug ( " dev_name %s n_target %d \n " , dev_name ( & dev - > dev ) , target_idx ) ;
2012-05-07 14:31:15 +04:00
device_lock ( & dev - > dev ) ;
2012-04-10 21:43:05 +04:00
for ( i = 0 ; i < dev - > n_targets ; i + + ) {
tg = & dev - > targets [ i ] ;
if ( tg - > idx = = target_idx )
break ;
}
if ( i = = dev - > n_targets ) {
2012-05-07 14:31:15 +04:00
device_unlock ( & dev - > dev ) ;
2012-04-10 21:43:05 +04:00
return - EINVAL ;
}
dev - > targets_generation + + ;
dev - > n_targets - - ;
2012-05-07 14:31:13 +04:00
dev - > active_target = NULL ;
2012-04-10 21:43:05 +04:00
if ( dev - > n_targets ) {
memcpy ( & dev - > targets [ i ] , & dev - > targets [ i + 1 ] ,
( dev - > n_targets - i ) * sizeof ( struct nfc_target ) ) ;
} else {
kfree ( dev - > targets ) ;
dev - > targets = NULL ;
}
2012-05-07 14:31:15 +04:00
device_unlock ( & dev - > dev ) ;
2012-04-10 21:43:05 +04:00
nfc_genl_target_lost ( dev , target_idx ) ;
return 0 ;
}
EXPORT_SYMBOL ( nfc_target_lost ) ;
2012-06-11 17:52:38 +04:00
inline void nfc_driver_failure ( struct nfc_dev * dev , int err )
2012-06-11 15:49:51 +04:00
{
2012-06-11 17:52:38 +04:00
nfc_targets_found ( dev , NULL , 0 ) ;
2012-06-11 15:49:51 +04:00
}
EXPORT_SYMBOL ( nfc_driver_failure ) ;
2013-05-10 17:28:38 +04:00
int nfc_add_se ( struct nfc_dev * dev , u32 se_idx , u16 type )
{
2013-05-10 18:15:32 +04:00
struct nfc_se * se ;
2013-05-10 17:47:37 +04:00
int rc ;
2013-05-10 17:28:38 +04:00
pr_debug ( " %s se index %d \n " , dev_name ( & dev - > dev ) , se_idx ) ;
2013-08-23 12:02:08 +04:00
se = nfc_find_se ( dev , se_idx ) ;
2013-05-10 18:15:32 +04:00
if ( se )
return - EALREADY ;
2013-05-10 17:28:38 +04:00
se = kzalloc ( sizeof ( struct nfc_se ) , GFP_KERNEL ) ;
if ( ! se )
return - ENOMEM ;
se - > idx = se_idx ;
se - > type = type ;
se - > state = NFC_SE_DISABLED ;
INIT_LIST_HEAD ( & se - > list ) ;
list_add ( & se - > list , & dev - > secure_elements ) ;
2013-05-10 17:47:37 +04:00
rc = nfc_genl_se_added ( dev , se_idx , type ) ;
if ( rc < 0 ) {
list_del ( & se - > list ) ;
kfree ( se ) ;
return rc ;
}
2013-05-10 17:28:38 +04:00
return 0 ;
}
EXPORT_SYMBOL ( nfc_add_se ) ;
int nfc_remove_se ( struct nfc_dev * dev , u32 se_idx )
{
struct nfc_se * se , * n ;
2013-05-10 17:47:37 +04:00
int rc ;
2013-05-10 17:28:38 +04:00
pr_debug ( " %s se index %d \n " , dev_name ( & dev - > dev ) , se_idx ) ;
list_for_each_entry_safe ( se , n , & dev - > secure_elements , list )
if ( se - > idx = = se_idx ) {
2013-05-10 17:47:37 +04:00
rc = nfc_genl_se_removed ( dev , se_idx ) ;
if ( rc < 0 )
return rc ;
2013-05-10 17:28:38 +04:00
list_del ( & se - > list ) ;
kfree ( se ) ;
return 0 ;
}
return - EINVAL ;
}
EXPORT_SYMBOL ( nfc_remove_se ) ;
2015-02-02 00:26:16 +03:00
int nfc_se_transaction ( struct nfc_dev * dev , u8 se_idx ,
struct nfc_evt_transaction * evt_transaction )
{
int rc ;
pr_debug ( " transaction: %x \n " , se_idx ) ;
device_lock ( & dev - > dev ) ;
if ( ! evt_transaction ) {
rc = - EPROTO ;
goto out ;
}
rc = nfc_genl_se_transaction ( dev , se_idx , evt_transaction ) ;
out :
device_unlock ( & dev - > dev ) ;
return rc ;
}
EXPORT_SYMBOL ( nfc_se_transaction ) ;
2011-07-02 02:31:33 +04:00
static void nfc_release ( struct device * d )
{
struct nfc_dev * dev = to_nfc_dev ( d ) ;
2013-05-10 17:53:29 +04:00
struct nfc_se * se , * n ;
2011-07-02 02:31:33 +04:00
2011-11-29 23:37:33 +04:00
pr_debug ( " dev_name=%s \n " , dev_name ( & dev - > dev ) ) ;
2011-07-02 02:31:33 +04:00
2011-07-02 02:31:34 +04:00
nfc_genl_data_exit ( & dev - > genl_data ) ;
kfree ( dev - > targets ) ;
2013-05-10 17:53:29 +04:00
list_for_each_entry_safe ( se , n , & dev - > secure_elements , list ) {
nfc_genl_se_removed ( dev , se - > idx ) ;
list_del ( & se - > list ) ;
kfree ( se ) ;
}
2011-07-02 02:31:33 +04:00
kfree ( dev ) ;
}
2012-04-10 21:43:12 +04:00
static void nfc_check_pres_work ( struct work_struct * work )
{
struct nfc_dev * dev = container_of ( work , struct nfc_dev ,
check_pres_work ) ;
int rc ;
device_lock ( & dev - > dev ) ;
2012-05-07 14:31:13 +04:00
if ( dev - > active_target & & timer_pending ( & dev - > check_pres_timer ) = = 0 ) {
rc = dev - > ops - > check_presence ( dev , dev - > active_target ) ;
2012-10-02 19:27:36 +04:00
if ( rc = = - EOPNOTSUPP )
goto exit ;
2012-11-26 21:06:27 +04:00
if ( rc ) {
2012-05-07 14:31:15 +04:00
u32 active_target_idx = dev - > active_target - > idx ;
device_unlock ( & dev - > dev ) ;
nfc_target_lost ( dev , active_target_idx ) ;
return ;
2012-04-10 21:43:12 +04:00
}
2012-11-26 21:06:27 +04:00
if ( ! dev - > shutting_down )
mod_timer ( & dev - > check_pres_timer , jiffies +
msecs_to_jiffies ( NFC_CHECK_PRES_FREQ_MS ) ) ;
2012-04-10 21:43:12 +04:00
}
2012-10-02 19:27:36 +04:00
exit :
2012-04-10 21:43:12 +04:00
device_unlock ( & dev - > dev ) ;
}
static void nfc_check_pres_timeout ( unsigned long data )
{
struct nfc_dev * dev = ( struct nfc_dev * ) data ;
2012-10-03 03:01:31 +04:00
schedule_work ( & dev - > check_pres_work ) ;
2012-04-10 21:43:12 +04:00
}
2011-07-02 02:31:33 +04:00
struct class nfc_class = {
. name = " nfc " ,
. dev_release = nfc_release ,
} ;
EXPORT_SYMBOL ( nfc_class ) ;
2013-02-01 23:40:17 +04:00
static int match_idx ( struct device * d , const void * data )
2011-07-02 02:31:33 +04:00
{
struct nfc_dev * dev = to_nfc_dev ( d ) ;
2013-02-01 23:40:17 +04:00
const unsigned int * idx = data ;
2011-07-02 02:31:33 +04:00
return dev - > idx = = * idx ;
}
2012-04-15 09:58:06 +04:00
struct nfc_dev * nfc_get_device ( unsigned int idx )
2011-07-02 02:31:33 +04:00
{
struct device * d ;
d = class_find_device ( & nfc_class , NULL , & idx , match_idx ) ;
if ( ! d )
return NULL ;
return to_nfc_dev ( d ) ;
}
/**
* nfc_allocate_device - allocate a new nfc device
*
* @ ops : device operations
* @ supported_protocols : NFC protocols supported by the device
*/
struct nfc_dev * nfc_allocate_device ( struct nfc_ops * ops ,
2012-03-05 04:03:53 +04:00
u32 supported_protocols ,
int tx_headroom , int tx_tailroom )
2011-07-02 02:31:33 +04:00
{
struct nfc_dev * dev ;
if ( ! ops - > start_poll | | ! ops - > stop_poll | | ! ops - > activate_target | |
2012-05-16 17:55:48 +04:00
! ops - > deactivate_target | | ! ops - > im_transceive )
2011-07-02 02:31:33 +04:00
return NULL ;
if ( ! supported_protocols )
return NULL ;
dev = kzalloc ( sizeof ( struct nfc_dev ) , GFP_KERNEL ) ;
if ( ! dev )
return NULL ;
dev - > ops = ops ;
dev - > supported_protocols = supported_protocols ;
2011-08-19 17:47:11 +04:00
dev - > tx_headroom = tx_headroom ;
dev - > tx_tailroom = tx_tailroom ;
2013-05-10 17:28:38 +04:00
INIT_LIST_HEAD ( & dev - > secure_elements ) ;
2011-07-02 02:31:33 +04:00
2011-07-02 02:31:34 +04:00
nfc_genl_data_init ( & dev - > genl_data ) ;
2012-10-05 13:05:45 +04:00
dev - > rf_mode = NFC_RF_NONE ;
2012-05-07 14:31:15 +04:00
2011-07-02 02:31:34 +04:00
/* first generation must not be 0 */
dev - > targets_generation = 1 ;
2012-04-10 21:43:12 +04:00
if ( ops - > check_presence ) {
init_timer ( & dev - > check_pres_timer ) ;
dev - > check_pres_timer . data = ( unsigned long ) dev ;
dev - > check_pres_timer . function = nfc_check_pres_timeout ;
INIT_WORK ( & dev - > check_pres_work , nfc_check_pres_work ) ;
}
2011-07-02 02:31:33 +04:00
return dev ;
}
EXPORT_SYMBOL ( nfc_allocate_device ) ;
/**
* nfc_register_device - register a nfc device in the nfc subsystem
*
* @ dev : The nfc device to register
*/
int nfc_register_device ( struct nfc_dev * dev )
{
int rc ;
2011-11-29 23:37:33 +04:00
pr_debug ( " dev_name=%s \n " , dev_name ( & dev - > dev ) ) ;
2011-07-02 02:31:33 +04:00
2012-10-22 17:57:58 +04:00
dev - > idx = ida_simple_get ( & nfc_index_ida , 0 , 0 , GFP_KERNEL ) ;
if ( dev - > idx < 0 )
return dev - > idx ;
dev - > dev . class = & nfc_class ;
dev_set_name ( & dev - > dev , " nfc%d " , dev - > idx ) ;
device_initialize ( & dev - > dev ) ;
2011-07-02 02:31:33 +04:00
mutex_lock ( & nfc_devlist_mutex ) ;
nfc_devlist_generation + + ;
rc = device_add ( & dev - > dev ) ;
mutex_unlock ( & nfc_devlist_mutex ) ;
2011-07-02 02:31:34 +04:00
if ( rc < 0 )
return rc ;
2011-12-14 19:43:12 +04:00
rc = nfc_llcp_register_device ( dev ) ;
if ( rc )
pr_err ( " Could not register llcp device \n " ) ;
2011-07-02 02:31:34 +04:00
rc = nfc_genl_device_added ( dev ) ;
if ( rc )
2011-11-29 23:37:33 +04:00
pr_debug ( " The userspace won't be notified that the device %s was added \n " ,
dev_name ( & dev - > dev ) ) ;
2011-07-02 02:31:34 +04:00
2013-04-11 13:52:20 +04:00
dev - > rfkill = rfkill_alloc ( dev_name ( & dev - > dev ) , & dev - > dev ,
RFKILL_TYPE_NFC , & nfc_rfkill_ops , dev ) ;
if ( dev - > rfkill ) {
if ( rfkill_register ( dev - > rfkill ) < 0 ) {
rfkill_destroy ( dev - > rfkill ) ;
dev - > rfkill = NULL ;
}
}
2011-07-02 02:31:34 +04:00
return 0 ;
2011-07-02 02:31:33 +04:00
}
EXPORT_SYMBOL ( nfc_register_device ) ;
/**
* nfc_unregister_device - unregister a nfc device in the nfc subsystem
*
* @ dev : The nfc device to unregister
*/
void nfc_unregister_device ( struct nfc_dev * dev )
{
2012-10-22 17:57:58 +04:00
int rc , id ;
2011-07-02 02:31:34 +04:00
2011-11-29 23:37:33 +04:00
pr_debug ( " dev_name=%s \n " , dev_name ( & dev - > dev ) ) ;
2011-07-02 02:31:33 +04:00
2012-10-22 17:57:58 +04:00
id = dev - > idx ;
2013-04-11 13:52:20 +04:00
if ( dev - > rfkill ) {
rfkill_unregister ( dev - > rfkill ) ;
rfkill_destroy ( dev - > rfkill ) ;
}
2012-11-26 21:06:27 +04:00
if ( dev - > ops - > check_presence ) {
device_lock ( & dev - > dev ) ;
dev - > shutting_down = true ;
device_unlock ( & dev - > dev ) ;
del_timer_sync ( & dev - > check_pres_timer ) ;
cancel_work_sync ( & dev - > check_pres_work ) ;
}
2011-07-02 02:31:33 +04:00
2012-11-26 21:06:27 +04:00
rc = nfc_genl_device_removed ( dev ) ;
if ( rc )
pr_debug ( " The userspace won't be notified that the device %s "
" was removed \n " , dev_name ( & dev - > dev ) ) ;
2011-07-02 02:31:34 +04:00
2011-12-14 19:43:12 +04:00
nfc_llcp_unregister_device ( dev ) ;
2012-11-26 21:06:27 +04:00
mutex_lock ( & nfc_devlist_mutex ) ;
nfc_devlist_generation + + ;
device_del ( & dev - > dev ) ;
mutex_unlock ( & nfc_devlist_mutex ) ;
2011-07-02 02:31:34 +04:00
2012-10-22 17:57:58 +04:00
ida_simple_remove ( & nfc_index_ida , id ) ;
2011-07-02 02:31:33 +04:00
}
EXPORT_SYMBOL ( nfc_unregister_device ) ;
static int __init nfc_init ( void )
{
2011-07-02 02:31:34 +04:00
int rc ;
2011-11-29 23:37:32 +04:00
pr_info ( " NFC Core ver %s \n " , VERSION ) ;
2011-07-02 02:31:33 +04:00
2011-07-02 02:31:34 +04:00
rc = class_register ( & nfc_class ) ;
if ( rc )
return rc ;
rc = nfc_genl_init ( ) ;
if ( rc )
goto err_genl ;
/* the first generation must not be 0 */
nfc_devlist_generation = 1 ;
2011-07-02 02:31:36 +04:00
rc = rawsock_init ( ) ;
if ( rc )
goto err_rawsock ;
2011-12-14 19:43:12 +04:00
rc = nfc_llcp_init ( ) ;
if ( rc )
goto err_llcp_sock ;
2011-07-02 02:31:35 +04:00
rc = af_nfc_init ( ) ;
if ( rc )
goto err_af_nfc ;
2011-07-02 02:31:34 +04:00
return 0 ;
2011-07-02 02:31:35 +04:00
err_af_nfc :
2011-12-14 19:43:12 +04:00
nfc_llcp_exit ( ) ;
err_llcp_sock :
2011-07-02 02:31:36 +04:00
rawsock_exit ( ) ;
err_rawsock :
2011-07-02 02:31:35 +04:00
nfc_genl_exit ( ) ;
2011-07-02 02:31:34 +04:00
err_genl :
class_unregister ( & nfc_class ) ;
return rc ;
2011-07-02 02:31:33 +04:00
}
static void __exit nfc_exit ( void )
{
2011-07-02 02:31:35 +04:00
af_nfc_exit ( ) ;
2011-12-14 19:43:12 +04:00
nfc_llcp_exit ( ) ;
2011-07-02 02:31:36 +04:00
rawsock_exit ( ) ;
2011-07-02 02:31:34 +04:00
nfc_genl_exit ( ) ;
2011-07-02 02:31:33 +04:00
class_unregister ( & nfc_class ) ;
}
subsys_initcall ( nfc_init ) ;
module_exit ( nfc_exit ) ;
MODULE_AUTHOR ( " Lauro Ramos Venancio <lauro.venancio@openbossa.org> " ) ;
MODULE_DESCRIPTION ( " NFC Core ver " VERSION ) ;
MODULE_VERSION ( VERSION ) ;
MODULE_LICENSE ( " GPL " ) ;
2012-06-12 02:35:50 +04:00
MODULE_ALIAS_NETPROTO ( PF_NFC ) ;
2012-06-12 18:54:16 +04:00
MODULE_ALIAS_GENL_FAMILY ( NFC_GENL_NAME ) ;