2013-06-06 18:23:23 +04:00
/*
* NFC hardware simulation driver
* 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 .
*
*/
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/module.h>
2016-07-19 12:58:16 +03:00
# include <linux/ctype.h>
# include <linux/debugfs.h>
2013-06-06 18:23:23 +04:00
# include <linux/nfc.h>
# include <net/nfc/nfc.h>
2016-06-23 12:20:26 +03:00
# include <net/nfc/digital.h>
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
# define NFCSIM_ERR(d, fmt, args...) nfc_err(&d->nfc_digital_dev->nfc_dev->dev, \
" %s: " fmt , __func__ , # # args )
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
# define NFCSIM_DBG(d, fmt, args...) dev_dbg(&d->nfc_digital_dev->nfc_dev->dev, \
" %s: " fmt , __func__ , # # args )
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
# define NFCSIM_VERSION "0.2"
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
# define NFCSIM_MODE_NONE 0
# define NFCSIM_MODE_INITIATOR 1
# define NFCSIM_MODE_TARGET 2
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
# define NFCSIM_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC | \
NFC_DIGITAL_DRV_CAPS_TG_CRC )
2015-12-20 21:59:30 +03:00
2013-06-06 18:23:23 +04:00
struct nfcsim {
2016-06-23 12:20:26 +03:00
struct nfc_digital_dev * nfc_digital_dev ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
struct work_struct recv_work ;
struct delayed_work send_work ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
struct nfcsim_link * link_in ;
struct nfcsim_link * link_out ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
bool up ;
u8 mode ;
u8 rf_tech ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
u16 recv_timeout ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
nfc_digital_cmd_complete_t cb ;
void * arg ;
2016-07-19 12:58:17 +03:00
u8 dropframe ;
2016-06-23 12:20:26 +03:00
} ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
struct nfcsim_link {
struct mutex lock ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
u8 rf_tech ;
u8 mode ;
2015-12-20 21:59:30 +03:00
2016-06-23 12:20:26 +03:00
u8 shutdown ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
struct sk_buff * skb ;
wait_queue_head_t recv_wait ;
u8 cond ;
2013-06-06 18:23:23 +04:00
} ;
2016-06-23 12:20:26 +03:00
static struct nfcsim_link * nfcsim_link_new ( void )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
struct nfcsim_link * link ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
link = kzalloc ( sizeof ( struct nfcsim_link ) , GFP_KERNEL ) ;
if ( ! link )
return NULL ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
mutex_init ( & link - > lock ) ;
init_waitqueue_head ( & link - > recv_wait ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
return link ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static void nfcsim_link_free ( struct nfcsim_link * link )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
dev_kfree_skb ( link - > skb ) ;
kfree ( link ) ;
}
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
static void nfcsim_link_recv_wake ( struct nfcsim_link * link )
{
link - > cond = 1 ;
wake_up_interruptible ( & link - > recv_wait ) ;
}
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
static void nfcsim_link_set_skb ( struct nfcsim_link * link , struct sk_buff * skb ,
u8 rf_tech , u8 mode )
{
mutex_lock ( & link - > lock ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
dev_kfree_skb ( link - > skb ) ;
link - > skb = skb ;
link - > rf_tech = rf_tech ;
link - > mode = mode ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
mutex_unlock ( & link - > lock ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static void nfcsim_link_recv_cancel ( struct nfcsim_link * link )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
mutex_lock ( & link - > lock ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
link - > mode = NFCSIM_MODE_NONE ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
mutex_unlock ( & link - > lock ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
nfcsim_link_recv_wake ( link ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static void nfcsim_link_shutdown ( struct nfcsim_link * link )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
mutex_lock ( & link - > lock ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
link - > shutdown = 1 ;
link - > mode = NFCSIM_MODE_NONE ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
mutex_unlock ( & link - > lock ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
nfcsim_link_recv_wake ( link ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static struct sk_buff * nfcsim_link_recv_skb ( struct nfcsim_link * link ,
int timeout , u8 rf_tech , u8 mode )
2013-06-06 18:23:23 +04:00
{
int rc ;
2016-06-23 12:20:26 +03:00
struct sk_buff * skb ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
rc = wait_event_interruptible_timeout ( link - > recv_wait ,
link - > cond ,
msecs_to_jiffies ( timeout ) ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
mutex_lock ( & link - > lock ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
skb = link - > skb ;
link - > skb = NULL ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
if ( ! rc ) {
rc = - ETIMEDOUT ;
goto done ;
}
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
if ( ! skb | | link - > rf_tech ! = rf_tech | | link - > mode = = mode ) {
rc = - EINVAL ;
goto done ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
if ( link - > shutdown ) {
rc = - ENODEV ;
goto done ;
}
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
done :
mutex_unlock ( & link - > lock ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
if ( rc < 0 ) {
dev_kfree_skb ( skb ) ;
skb = ERR_PTR ( rc ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
link - > cond = 0 ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
return skb ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static void nfcsim_send_wq ( struct work_struct * work )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
struct nfcsim * dev = container_of ( work , struct nfcsim , send_work . work ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
/*
* To effectively send data , the device just wake up its link_out which
* is the link_in of the peer device . The exchanged skb has already been
* stored in the dev - > link_out through nfcsim_link_set_skb ( ) .
*/
nfcsim_link_recv_wake ( dev - > link_out ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static void nfcsim_recv_wq ( struct work_struct * work )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
struct nfcsim * dev = container_of ( work , struct nfcsim , recv_work ) ;
struct sk_buff * skb ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
skb = nfcsim_link_recv_skb ( dev - > link_in , dev - > recv_timeout ,
dev - > rf_tech , dev - > mode ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
if ( ! dev - > up ) {
NFCSIM_ERR ( dev , " Device is down \n " ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
if ( ! IS_ERR ( skb ) )
dev_kfree_skb ( skb ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
skb = ERR_PTR ( - ENODEV ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
dev - > cb ( dev - > nfc_digital_dev , dev - > arg , skb ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static int nfcsim_send ( struct nfc_digital_dev * ddev , struct sk_buff * skb ,
u16 timeout , nfc_digital_cmd_complete_t cb , void * arg )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
struct nfcsim * dev = nfc_digital_get_drvdata ( ddev ) ;
u8 delay ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
if ( ! dev - > up ) {
NFCSIM_ERR ( dev , " Device is down \n " ) ;
return - ENODEV ;
}
dev - > recv_timeout = timeout ;
dev - > cb = cb ;
dev - > arg = arg ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
schedule_work ( & dev - > recv_work ) ;
2013-06-06 18:23:23 +04:00
2016-07-19 12:58:17 +03:00
if ( dev - > dropframe ) {
NFCSIM_DBG ( dev , " dropping frame (out of %d) \n " , dev - > dropframe ) ;
dev_kfree_skb ( skb ) ;
dev - > dropframe - - ;
return 0 ;
}
2016-06-23 12:20:26 +03:00
if ( skb ) {
nfcsim_link_set_skb ( dev - > link_out , skb , dev - > rf_tech ,
dev - > mode ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
/* Add random delay (between 3 and 10 ms) before sending data */
get_random_bytes ( & delay , 1 ) ;
delay = 3 + ( delay & 0x07 ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
schedule_delayed_work ( & dev - > send_work , msecs_to_jiffies ( delay ) ) ;
}
return 0 ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static void nfcsim_abort_cmd ( struct nfc_digital_dev * ddev )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
struct nfcsim * dev = nfc_digital_get_drvdata ( ddev ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
nfcsim_link_recv_cancel ( dev - > link_in ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static int nfcsim_switch_rf ( struct nfc_digital_dev * ddev , bool on )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
struct nfcsim * dev = nfc_digital_get_drvdata ( ddev ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
dev - > up = on ;
return 0 ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static int nfcsim_in_configure_hw ( struct nfc_digital_dev * ddev ,
int type , int param )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
struct nfcsim * dev = nfc_digital_get_drvdata ( ddev ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
switch ( type ) {
case NFC_DIGITAL_CONFIG_RF_TECH :
dev - > up = true ;
dev - > mode = NFCSIM_MODE_INITIATOR ;
dev - > rf_tech = param ;
break ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
case NFC_DIGITAL_CONFIG_FRAMING :
break ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
default :
NFCSIM_ERR ( dev , " Invalid configuration type: %d \n " , type ) ;
return - EINVAL ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
return 0 ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static int nfcsim_in_send_cmd ( struct nfc_digital_dev * ddev ,
struct sk_buff * skb , u16 timeout ,
nfc_digital_cmd_complete_t cb , void * arg )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
return nfcsim_send ( ddev , skb , timeout , cb , arg ) ;
}
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
static int nfcsim_tg_configure_hw ( struct nfc_digital_dev * ddev ,
int type , int param )
{
struct nfcsim * dev = nfc_digital_get_drvdata ( ddev ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
switch ( type ) {
case NFC_DIGITAL_CONFIG_RF_TECH :
dev - > up = true ;
dev - > mode = NFCSIM_MODE_TARGET ;
dev - > rf_tech = param ;
break ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
case NFC_DIGITAL_CONFIG_FRAMING :
break ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
default :
NFCSIM_ERR ( dev , " Invalid configuration type: %d \n " , type ) ;
return - EINVAL ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
return 0 ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static int nfcsim_tg_send_cmd ( struct nfc_digital_dev * ddev ,
struct sk_buff * skb , u16 timeout ,
nfc_digital_cmd_complete_t cb , void * arg )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
return nfcsim_send ( ddev , skb , timeout , cb , arg ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static int nfcsim_tg_listen ( struct nfc_digital_dev * ddev , u16 timeout ,
nfc_digital_cmd_complete_t cb , void * arg )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
return nfcsim_send ( ddev , NULL , timeout , cb , arg ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static struct nfc_digital_ops nfcsim_digital_ops = {
. in_configure_hw = nfcsim_in_configure_hw ,
. in_send_cmd = nfcsim_in_send_cmd ,
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
. tg_listen = nfcsim_tg_listen ,
. tg_configure_hw = nfcsim_tg_configure_hw ,
. tg_send_cmd = nfcsim_tg_send_cmd ,
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
. abort_cmd = nfcsim_abort_cmd ,
. switch_rf = nfcsim_switch_rf ,
} ;
2013-06-06 18:23:23 +04:00
2016-07-19 12:58:16 +03:00
static struct dentry * nfcsim_debugfs_root ;
static void nfcsim_debugfs_init ( void )
{
nfcsim_debugfs_root = debugfs_create_dir ( " nfcsim " , NULL ) ;
if ( ! nfcsim_debugfs_root )
pr_err ( " Could not create debugfs entry \n " ) ;
}
static void nfcsim_debugfs_remove ( void )
{
debugfs_remove_recursive ( nfcsim_debugfs_root ) ;
}
static void nfcsim_debugfs_init_dev ( struct nfcsim * dev )
{
struct dentry * dev_dir ;
char devname [ 5 ] ; /* nfcX\0 */
u32 idx ;
int n ;
if ( ! nfcsim_debugfs_root ) {
NFCSIM_ERR ( dev , " nfcsim debugfs not initialized \n " ) ;
return ;
}
idx = dev - > nfc_digital_dev - > nfc_dev - > idx ;
n = snprintf ( devname , sizeof ( devname ) , " nfc%d " , idx ) ;
if ( n > = sizeof ( devname ) ) {
NFCSIM_ERR ( dev , " Could not compute dev name for dev %d \n " , idx ) ;
return ;
}
dev_dir = debugfs_create_dir ( devname , nfcsim_debugfs_root ) ;
if ( ! dev_dir ) {
NFCSIM_ERR ( dev , " Could not create debugfs entries for nfc%d \n " ,
idx ) ;
return ;
}
2016-07-19 12:58:17 +03:00
debugfs_create_u8 ( " dropframe " , 0664 , dev_dir , & dev - > dropframe ) ;
2016-07-19 12:58:16 +03:00
}
2016-06-23 12:20:26 +03:00
static struct nfcsim * nfcsim_device_new ( struct nfcsim_link * link_in ,
struct nfcsim_link * link_out )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
struct nfcsim * dev ;
int rc ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
dev = kzalloc ( sizeof ( struct nfcsim ) , GFP_KERNEL ) ;
if ( ! dev )
return ERR_PTR ( - ENOMEM ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
INIT_DELAYED_WORK ( & dev - > send_work , nfcsim_send_wq ) ;
INIT_WORK ( & dev - > recv_work , nfcsim_recv_wq ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
dev - > nfc_digital_dev =
nfc_digital_allocate_device ( & nfcsim_digital_ops ,
NFC_PROTO_NFC_DEP_MASK ,
NFCSIM_CAPABILITIES ,
0 , 0 ) ;
if ( ! dev - > nfc_digital_dev ) {
kfree ( dev ) ;
return ERR_PTR ( - ENOMEM ) ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
nfc_digital_set_drvdata ( dev - > nfc_digital_dev , dev ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
dev - > link_in = link_in ;
dev - > link_out = link_out ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
rc = nfc_digital_register_device ( dev - > nfc_digital_dev ) ;
if ( rc ) {
pr_err ( " Could not register digital device (%d) \n " , rc ) ;
nfc_digital_free_device ( dev - > nfc_digital_dev ) ;
kfree ( dev ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
return ERR_PTR ( rc ) ;
2013-06-06 18:23:23 +04:00
}
2016-07-19 12:58:16 +03:00
nfcsim_debugfs_init_dev ( dev ) ;
2016-06-23 12:20:26 +03:00
return dev ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
static void nfcsim_device_free ( struct nfcsim * dev )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
nfc_digital_unregister_device ( dev - > nfc_digital_dev ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
dev - > up = false ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
nfcsim_link_shutdown ( dev - > link_in ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
cancel_delayed_work_sync ( & dev - > send_work ) ;
cancel_work_sync ( & dev - > recv_work ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
nfc_digital_free_device ( dev - > nfc_digital_dev ) ;
2013-06-06 18:23:23 +04:00
kfree ( dev ) ;
}
2016-06-23 12:20:26 +03:00
static struct nfcsim * dev0 ;
static struct nfcsim * dev1 ;
2013-06-06 18:23:23 +04:00
2013-06-24 14:02:28 +04:00
static int __init nfcsim_init ( void )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
struct nfcsim_link * link0 , * link1 ;
2013-06-06 18:23:23 +04:00
int rc ;
2016-06-23 12:20:26 +03:00
link0 = nfcsim_link_new ( ) ;
link1 = nfcsim_link_new ( ) ;
if ( ! link0 | | ! link1 ) {
2013-06-06 18:23:23 +04:00
rc = - ENOMEM ;
2016-06-23 12:20:26 +03:00
goto exit_err ;
2013-06-06 18:23:23 +04:00
}
2016-07-19 12:58:16 +03:00
nfcsim_debugfs_init ( ) ;
2016-06-23 12:20:26 +03:00
dev0 = nfcsim_device_new ( link0 , link1 ) ;
2013-06-06 18:23:23 +04:00
if ( IS_ERR ( dev0 ) ) {
rc = PTR_ERR ( dev0 ) ;
2016-06-23 12:20:26 +03:00
goto exit_err ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
dev1 = nfcsim_device_new ( link1 , link0 ) ;
2013-06-06 18:23:23 +04:00
if ( IS_ERR ( dev1 ) ) {
2016-06-23 12:20:26 +03:00
nfcsim_device_free ( dev0 ) ;
2013-06-06 18:23:23 +04:00
rc = PTR_ERR ( dev1 ) ;
2016-06-23 12:20:26 +03:00
goto exit_err ;
2013-06-06 18:23:23 +04:00
}
2016-06-23 12:20:26 +03:00
pr_info ( " nfcsim " NFCSIM_VERSION " initialized \n " ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
return 0 ;
exit_err :
pr_err ( " Failed to initialize nfcsim driver (%d) \n " , rc ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
nfcsim_link_free ( link0 ) ;
nfcsim_link_free ( link1 ) ;
2013-06-06 18:23:23 +04:00
return rc ;
}
2013-06-24 14:02:28 +04:00
static void __exit nfcsim_exit ( void )
2013-06-06 18:23:23 +04:00
{
2016-06-23 12:20:26 +03:00
struct nfcsim_link * link0 , * link1 ;
link0 = dev0 - > link_in ;
link1 = dev0 - > link_out ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
nfcsim_device_free ( dev0 ) ;
nfcsim_device_free ( dev1 ) ;
2013-06-06 18:23:23 +04:00
2016-06-23 12:20:26 +03:00
nfcsim_link_free ( link0 ) ;
nfcsim_link_free ( link1 ) ;
2016-07-19 12:58:16 +03:00
nfcsim_debugfs_remove ( ) ;
2013-06-06 18:23:23 +04:00
}
module_init ( nfcsim_init ) ;
module_exit ( nfcsim_exit ) ;
MODULE_DESCRIPTION ( " NFCSim driver ver " NFCSIM_VERSION ) ;
MODULE_VERSION ( NFCSIM_VERSION ) ;
MODULE_LICENSE ( " GPL " ) ;