@ -18,523 +18,427 @@
# include <linux/module.h>
# include <linux/nfc.h>
# include <net/nfc/nfc.h>
# include <net/nfc/digital.h>
# define DEV_ERR(_dev, fmt, args...) nfc_err(& _dev->nfc_dev->dev, \
" %s: " fmt , __func__ , # # args )
# define NFCSIM_ERR(d, fmt, args...) nfc_err(&d->nfc_digital _dev->nfc_dev->dev, \
" %s: " fmt , __func__ , # # args )
# define DEV_DBG(_dev, fmt, args...) dev_dbg(& _dev->nfc_dev->dev, \
" %s: " fmt , __func__ , # # args )
# define NFCSIM_DBG(d, fmt, args...) dev_dbg(&d->nfc_digital _dev->nfc_dev->dev, \
" %s: " fmt , __func__ , # # args )
# define NFCSIM_VERSION "0.1 "
# define NFCSIM_VERSION "0.2 "
# define NFCSIM_POLL_NONE 0
# define NFCSIM_POLL_INITIATOR 1
# define NFCSIM_POLL_TARGET 2
# define NFCSIM_POLL_DUAL (NFCSIM_POLL_INITIATOR | NFCSIM_POLL_TARGET)
# define NFCSIM_MODE_NONE 0
# define NFCSIM_MODE_INITIATOR 1
# define NFCSIM_MODE_TARGET 2
# define RX_DEFAULT_DELAY 5
# define NFCSIM_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC | \
NFC_DIGITAL_DRV_CAPS_TG_CRC )
struct nfcsim {
struct nfc_dev * nfc_dev ;
struct nfc_digital_d ev * nfc_digital _dev ;
struct mutex lock ;
struct delayed_work recv_work ;
struct work_struct recv_work ;
struct delayed_work send_work ;
struct sk_buff * clone_skb ;
struct nfcsim_link * link_in ;
struct nfcsim_link * link_out ;
struct delayed_work poll_work ;
u8 polling_ mode;
u8 curr_polling_mode ;
bool up ;
u8 mode ;
u8 rf_tech ;
u8 shutting_down ;
u16 recv_timeout ;
u8 up ;
nfc_digital_cmd_complete_t cb ;
void * arg ;
} ;
u8 initiator ;
struct nfcsim_link {
struct mutex lock ;
u32 rx_delay ;
u8 rf_tech ;
u8 mode ;
data_exchange_cb_t cb ;
void * cb_context ;
u8 shutdown ;
struct nfcsim * peer_dev ;
struct sk_buff * skb ;
wait_queue_head_t recv_wait ;
u8 cond ;
} ;
static struct nfcsim * dev0 ;
static struct nfcsim * dev1 ;
static struct workqueue_struct * wq ;
static void nfcsim_cleanup_dev ( struct nfcsim * dev , u8 shutdown )
static struct nfcsim_link * nfcsim_link_new ( void )
{
DEV_DBG ( dev , " shutdown=%d \n " , shutdown ) ;
mutex_lock ( & dev - > lock ) ;
struct nfcsim_link * link ;
dev - > polling_mode = NFCSIM_POLL_NONE ;
dev - > shutting_down = shutdown ;
dev - > cb = NULL ;
dev_kfree_skb ( dev - > clone_skb ) ;
dev - > clone_skb = NULL ;
link = kzalloc ( sizeof ( struct nfcsim_link ) , GFP_KERNEL ) ;
if ( ! link )
return NULL ;
mutex_unlock ( & dev - > lock ) ;
mutex_init ( & link - > lock ) ;
init_waitqueue_head ( & link - > recv_wait ) ;
cancel_delayed_work_sync ( & dev - > poll_work ) ;
cancel_delayed_work_sync ( & dev - > recv_work ) ;
return link ;
}
static int nfcsim_target_found ( struct nfcsim * dev )
static void nfcsim_link_free ( struct nfcsim_link * link )
{
struct nfc_target nfc_tgt ;
dev_kfree_skb ( link - > skb ) ;
kfree ( link ) ;
}
DEV_DBG ( dev , " \n " ) ;
static void nfcsim_link_recv_wake ( struct nfcsim_link * link )
{
link - > cond = 1 ;
wake_up_interruptible ( & link - > recv_wait ) ;
}
memset ( & nfc_tgt , 0 , sizeof ( struct nfc_target ) ) ;
static void nfcsim_link_set_skb ( struct nfcsim_link * link , struct sk_buff * skb ,
u8 rf_tech , u8 mode )
{
mutex_lock ( & link - > lock ) ;
nfc_tgt . supported_protocols = NFC_PROTO_NFC_DEP_MASK ;
nfc_targets_found ( dev - > nfc_dev , & nfc_tgt , 1 ) ;
dev_kfree_skb ( link - > skb ) ;
link - > skb = skb ;
link - > rf_tech = rf_tech ;
link - > mode = mode ;
return 0 ;
mutex_unlock ( & link - > lock ) ;
}
static int nfcsim_dev_up ( struct nfc_dev * nfc_dev )
static void nfcsim_link_recv_cancel ( struct nfcsim_link * link )
{
struct nfcsim * dev = nfc_get_drvdata ( nfc_dev ) ;
mutex_lock ( & link - > lock ) ;
DEV_DBG ( dev , " \n " ) ;
link - > mode = NFCSIM_MODE_NONE ;
mutex_lock ( & dev - > lock ) ;
mutex_un lock ( & link - > lock ) ;
dev - > up = 1 ;
mutex_unlock ( & dev - > lock ) ;
return 0 ;
nfcsim_link_recv_wake ( link ) ;
}
static int nfcsim_dev_down ( struct nfc_dev * nfc_dev )
static void nfcsim_link_shutdown ( struct nfcsim_link * link )
{
struct nfcsim * dev = nfc_get_drvdata ( nfc_dev ) ;
DEV_DBG ( dev , " \n " ) ;
mutex_lock ( & link - > lock ) ;
mutex_lock ( & dev - > lock ) ;
link - > shutdown = 1 ;
link - > mode = NFCSIM_MODE_NONE ;
dev - > up = 0 ;
mutex_unlock ( & link - > lock ) ;
mutex_unlock ( & dev - > lock ) ;
return 0 ;
nfcsim_link_recv_wake ( link ) ;
}
static int nfcsim_dep_link_up ( struct nfc_dev * nfc_dev ,
struct nfc_target * target ,
u8 comm_mode , u8 * gb , size_t gb_len )
static struct sk_buff * nfcsim_link_recv_skb ( struct nfcsim_link * link ,
int timeout , u8 rf_tech , u8 mode )
{
int rc ;
struct nfcsim * dev = nfc_get_drvdata ( nfc_dev ) ;
struct nfcsim * peer = dev - > peer_dev ;
u8 * remote_gb ;
size_t remote_gb_len ;
struct sk_buff * skb ;
DEV_DBG ( dev , " target_idx: %d, comm_mode: %d \n " , target - > idx , comm_mode ) ;
rc = wait_event_interruptible_timeout ( link - > recv_wait ,
link - > cond ,
msecs_to_jiffies ( timeout ) ) ;
mutex_lock ( & peer - > lock ) ;
mutex_lock ( & link - > lock ) ;
nfc_tm_activated ( peer - > nfc_dev , NFC_PROTO_NFC_DEP_MASK ,
NFC_COMM_ACTIVE , gb , gb_len ) ;
skb = link - > skb ;
link - > skb = NULL ;
remote_gb = nfc_get_local_general_bytes ( peer - > nfc_dev , & remote_gb_len ) ;
if ( ! remote_gb ) {
DEV_ERR ( peer , " Can't get remote general bytes \n " ) ;
if ( ! rc ) {
rc = - ETIMEDOUT ;
goto done ;
}
mutex_unlock ( & peer - > lock ) ;
return - EINVAL ;
if ( ! skb | | link - > rf_tech ! = rf_tech | | link - > mode = = mode ) {
rc = - EINVAL ;
goto done ;
}
mutex_unlock ( & peer - > lock ) ;
if ( link - > shutdown ) {
rc = - ENODEV ;
goto done ;
}
mutex_lock ( & dev - > lock ) ;
done :
mutex_unlock ( & link - > lock ) ;
rc = nfc_set_remote_general_bytes ( nfc_dev , remote_gb , remote_gb_len ) ;
if ( rc ) {
DEV_ERR ( dev , " Can't set remote general bytes \n " ) ;
mutex_unlock ( & dev - > lock ) ;
return rc ;
if ( rc < 0 ) {
dev_kfree_skb ( skb ) ;
skb = ERR_PTR ( rc ) ;
}
rc = nfc_dep_link_is_up ( nfc_dev , target - > idx , NFC_COMM_ACTIVE ,
NFC_RF_INITIATOR ) ;
mutex_unlock ( & dev - > lock ) ;
link - > cond = 0 ;
return rc ;
return skb ;
}
static int nfcsim_dep_link_down ( struct nfc_dev * nfc_dev )
static void nfcsim_send_wq ( struct work_struct * work )
{
struct nfcsim * dev = nfc_get_drvdata ( nfc_dev ) ;
struct nfcsim * dev = container_of ( work , struct nfcsim , send_work . work ) ;
DEV_DBG ( dev , " \n " ) ;
nfcsim_cleanup_dev ( dev , 0 ) ;
return 0 ;
/*
* 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 ) ;
}
static int nfcsim_start_poll ( struct nfc_dev * nfc_dev ,
u32 im_protocols , u32 tm_protocols )
static void nfcsim_recv_wq ( struct work_struct * work )
{
struct nfcsim * dev = nfc_get_drvdata ( nfc_dev ) ;
int rc ;
mutex_lock ( & dev - > lock ) ;
struct nfcsim * dev = container_of ( work , struct nfcsim , recv_work ) ;
struct sk_buff * skb ;
if ( dev - > polling_mode ! = NFCSIM_POLL_NONE ) {
DEV_ERR ( dev , " Already in polling mode \n " ) ;
rc = - EBUSY ;
goto exit ;
}
skb = nfcsim_link_recv_skb ( dev - > link_in , dev - > recv_timeout ,
dev - > rf_tech , dev - > mode ) ;
if ( im_protocols & NFC_PROTO_NFC_DEP_MASK )
dev - > polling_mode | = NFCSIM_POLL_INITIATOR ;
if ( ! dev - > up ) {
NFCSIM_ERR ( dev , " Device is down \n " ) ;
if ( tm_protocols & NFC_PROTO_NFC_DEP_MASK )
dev - > polling_mode | = NFCSIM_POLL_TARGET ;
if ( ! IS_ERR ( skb ) )
dev_kfree_skb ( skb ) ;
if ( dev - > polling_mode = = NFCSIM_POLL_NONE ) {
DEV_ERR ( dev , " Unsupported polling mode \n " ) ;
rc = - EINVAL ;
goto exit ;
skb = ERR_PTR ( - ENODEV ) ;
}
dev - > initiator = 0 ;
dev - > curr_polling_mode = NFCSIM_POLL_NONE ;
queue_delayed_work ( wq , & dev - > poll_work , 0 ) ;
DEV_DBG ( dev , " Start polling: im: 0x%X, tm: 0x%X \n " , im_protocols ,
tm_protocols ) ;
rc = 0 ;
exit :
mutex_unlock ( & dev - > lock ) ;
return rc ;
dev - > cb ( dev - > nfc_digital_dev , dev - > arg , skb ) ;
}
static void nfcsim_stop_poll ( struct nfc_dev * nfc_dev )
static int nfcsim_send ( struct nfc_digital_dev * ddev , struct sk_buff * skb ,
u16 timeout , nfc_digital_cmd_complete_t cb , void * arg )
{
struct nfcsim * dev = nfc_get_drvdata ( nfc_dev ) ;
struct nfcsim * dev = nfc_digital_get_drvdata ( ddev ) ;
u8 delay ;
DEV_DBG ( dev , " Stop poll \n " ) ;
if ( ! dev - > up ) {
NFCSIM_ERR ( dev , " Device is down \n " ) ;
return - ENODEV ;
}
dev - > recv_timeout = timeout ;
dev - > cb = cb ;
dev - > arg = arg ;
mutex_lock ( & dev - > lock ) ;
schedule_wor k( & dev - > recv_wor k) ;
dev - > polling_mode = NFCSIM_POLL_NONE ;
if ( skb ) {
nfcsim_link_set_skb ( dev - > link_out , skb , dev - > rf_tech ,
dev - > mode ) ;
mutex_unlock ( & dev - > lock ) ;
/* Add random delay (between 3 and 10 ms) before sending data */
get_random_bytes ( & delay , 1 ) ;
delay = 3 + ( delay & 0x07 ) ;
cancel_delayed_work_sync ( & dev - > poll_work ) ;
schedule_delayed_work ( & dev - > send_work , msecs_to_jiffies ( delay ) ) ;
}
return 0 ;
}
static int nfcsim_activate_target ( struct nfc_dev * nfc_dev ,
struct nfc_target * target , u32 protocol )
static void nfcsim_abort_cmd ( struct nfc_digital_dev * ddev )
{
struct nfcsim * dev = nfc_get_drvdata ( nfc_dev ) ;
DEV_DBG ( dev , " \n " ) ;
struct nfcsim * dev = nfc_digital_get_drvdata ( ddev ) ;
return - ENOTSUPP ;
nfcsim_link_recv_cancel ( dev - > link_in ) ;
}
static void nfcsim_deactivate_target ( struct nfc_dev * nfc_dev ,
struct nfc_target * target , u8 mode )
static int nfcsim_switch_rf ( struct nfc_digital_dev * ddev , bool on )
{
struct nfcsim * dev = nfc_get_drvdata ( nfc_ dev) ;
struct nfcsim * dev = nfc_digital_ get_drvdata ( d dev) ;
DEV_DBG ( dev , " \n " ) ;
dev - > up = on ;
return 0 ;
}
static void nfcsim_wq_recv ( struct work_struct * work )
static int nfcsim_in_configure_hw ( struct nfc_digital_dev * ddev ,
int type , int param )
{
struct nfcsim * dev = container_of ( work , struct nfcsim ,
recv_work . work ) ;
struct nfcsim * dev = nfc_digital_get_drvdata ( ddev ) ;
mutex_lock ( & dev - > lock ) ;
switch ( type ) {
case NFC_DIGITAL_CONFIG_RF_TECH :
dev - > up = true ;
dev - > mode = NFCSIM_MODE_INITIATOR ;
dev - > rf_tech = param ;
break ;
if ( dev - > shutting_down | | ! dev - > up | | ! dev - > clone_skb ) {
dev_kfree_skb ( dev - > clone_skb ) ;
goto exit ;
}
case NFC_DIGITAL_CONFIG_FRAMING :
break ;
if ( dev - > initiator ) {
if ( ! dev - > cb ) {
DEV_ERR ( dev , " Null recv callback \n " ) ;
dev_kfree_skb ( dev - > clone_skb ) ;
goto exit ;
}
dev - > cb ( dev - > cb_context , dev - > clone_skb , 0 ) ;
dev - > cb = NULL ;
} else {
nfc_tm_data_received ( dev - > nfc_dev , dev - > clone_skb ) ;
default :
NFCSIM_ERR ( dev , " Invalid configuration type: %d \n " , type ) ;
return - EINVAL ;
}
exit :
dev - > clone_skb = NULL ;
mutex_unlock ( & dev - > lock ) ;
return 0 ;
}
static int nfcsim_tx ( struct nfc_dev * nfc_dev , struct nfc_target * target ,
struct sk_buff * skb , data_exchange_cb_t cb ,
void * cb_context )
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 )
{
struct nfcsim * dev = nfc_get_drvdata ( nfc_dev ) ;
struct nfcsim * peer = dev - > peer_dev ;
int err ;
mutex_lock ( & dev - > lock ) ;
if ( dev - > shutting_down | | ! dev - > up ) {
mutex_unlock ( & dev - > lock ) ;
err = - ENODEV ;
goto exit ;
}
dev - > cb = cb ;
dev - > cb_context = cb_context ;
return nfcsim_send ( ddev , skb , timeout , cb , arg ) ;
}
mutex_unlock ( & dev - > lock ) ;
static int nfcsim_tg_configure_hw ( struct nfc_digital_dev * ddev ,
int type , int param )
{
struct nfcsim * dev = nfc_digital_get_drvdata ( ddev ) ;
mutex_lock ( & peer - > lock ) ;
switch ( type ) {
case NFC_DIGITAL_CONFIG_RF_TECH :
dev - > up = true ;
dev - > mode = NFCSIM_MODE_TARGET ;
dev - > rf_tech = param ;
break ;
peer - > clone_skb = skb_clone ( skb , GFP_KERNEL ) ;
case NFC_DIGITAL_CONFIG_FRAMING :
break ;
if ( ! peer - > clone_skb ) {
DEV_ERR ( dev , " skb_clone failed \n " ) ;
mutex_unlock ( & peer - > lock ) ;
err = - ENOMEM ;
goto exit ;
default :
NFCSIM_ERR ( dev , " Invalid configuration type: %d \n " , type ) ;
return - EINVAL ;
}
/* This simulates an arbitrary transmission delay between the 2 devices.
* If packet transmission occurs immediately between them , we have a
* non - stop flow of several tens of thousands SYMM packets per second
* and a burning cpu .
*/
queue_delayed_work ( wq , & peer - > recv_work ,
msecs_to_jiffies ( dev - > rx_delay ) ) ;
mutex_unlock ( & peer - > lock ) ;
err = 0 ;
exit :
dev_kfree_skb ( skb ) ;
return err ;
return 0 ;
}
static int nfcsim_im_transceive ( struct nfc_dev * nfc_ dev,
struct nfc_target * target , struct sk_buff * skb ,
data_exchange_cb _t cb , void * cb_context )
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 )
{
return nfcsim_tx ( nfc_dev , target , skb , cb , cb_context ) ;
return nfcsim_send ( ddev , skb , timeout , cb , arg ) ;
}
static int nfcsim_tm_send ( struct nfc_dev * nfc_dev , struct sk_buff * skb )
static int nfcsim_tg_listen ( struct nfc_digital_dev * ddev , u16 timeout ,
nfc_digital_cmd_complete_t cb , void * arg )
{
return nfcsim_tx ( nfc_ dev , NULL , skb , NULL , NULL ) ;
return nfcsim_send ( ddev , NULL , timeout , cb , arg ) ;
}
static struct nfc_ops nfcsim_nfc_ops = {
. dev_up = nfcsim_dev_up ,
. dev_down = nfcsim_dev_down ,
. dep_link_up = nfcsim_dep_link_up ,
. dep_link_down = nfcsim_dep_link_down ,
. start_poll = nfcsim_start_poll ,
. stop_poll = nfcsim_stop_poll ,
. activate_target = nfcsim_activate_target ,
. deactivate_target = nfcsim_deactivate_target ,
. im_transceive = nfcsim_im_transceive ,
. tm_send = nfcsim_tm_send ,
} ;
static void nfcsim_set_polling_mode ( struct nfcsim * dev )
{
if ( dev - > polling_mode = = NFCSIM_POLL_NONE ) {
dev - > curr_polling_mode = NFCSIM_POLL_NONE ;
return ;
}
static struct nfc_digital_ops nfcsim_digital_ops = {
. in_configure_hw = nfcsim_in_configure_hw ,
. in_send_cmd = nfcsim_in_send_cmd ,
if ( dev - > curr_polling_mode = = NFCSIM_POLL_NONE ) {
if ( dev - > polling_mode & NFCSIM_POLL_INITIATOR )
dev - > curr_polling_mode = NFCSIM_POLL_INITIATOR ;
else
dev - > curr_polling_mode = NFCSIM_POLL_TARGET ;
. tg_listen = nfcsim_tg_listen ,
. tg_configure_hw = nfcsim_tg_configure_hw ,
. tg_send_cmd = nfcsim_tg_send_cmd ,
return ;
}
if ( dev - > polling_mode = = NFCSIM_POLL_DUAL ) {
if ( dev - > curr_polling_mode = = NFCSIM_POLL_TARGET )
dev - > curr_polling_mode = NFCSIM_POLL_INITIATOR ;
else
dev - > curr_polling_mode = NFCSIM_POLL_TARGET ;
}
}
. abort_cmd = nfcsim_abort_cmd ,
. switch_rf = nfcsim_switch_rf ,
} ;
static void nfcsim_wq_poll ( struct work_struct * work )
static struct nfcsim * nfcsim_device_new ( struct nfcsim_link * link_in ,
struct nfcsim_link * link_out )
{
struct nfcsim * dev = container_of ( work , struct nfcsim , poll_work . work ) ;
struct nfcsim * peer = dev - > peer_dev ;
struct nfcsim * dev ;
int rc ;
/* These work items run on an ordered workqueue and are therefore
* serialized . So we can take both mutexes without being dead locked .
*/
mutex_lock ( & dev - > lock ) ;
mutex_lock ( & peer - > lock ) ;
dev = kzalloc ( sizeof ( struct nfcsim ) , GFP_KERNEL ) ;
if ( ! dev )
return ERR_PTR ( - ENOMEM ) ;
nfcsim_set_polling_mode ( dev ) ;
INIT_DELAYED_WORK ( & dev - > send_work , nfcsim_send_wq ) ;
INIT_WORK ( & dev - > recv_work , nfcsim_recv_wq ) ;
if ( dev - > curr_polling_mode = = NFCSIM_POLL_NONE ) {
DEV_DBG ( dev , " Not polling \n " ) ;
goto unlock ;
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 ) ;
}
DEV_DBG ( dev , " Polling as %s " ,
dev - > curr_polling_mode = = NFCSIM_POLL_INITIATOR ?
" initiator \n " : " target \n " ) ;
if ( dev - > curr_polling_mode = = NFCSIM_POLL_TARGET )
goto sched_work ;
nfc_digital_set_drvdata ( dev - > nfc_digital_dev , dev ) ;
if ( peer - > curr_polling_mode = = NFCSIM_POLL_TARGET ) {
peer - > polling_mode = NFCSIM_POLL_NONE ;
dev - > polling_mode = NFCSIM_POLL_NONE ;
dev - > link_in = link_in ;
dev - > link_out = link_out ;
dev - > initiator = 1 ;
nfcsim_target_found ( dev ) ;
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 ) ;
goto unlock ;
return ERR_PTR ( rc ) ;
}
sched_work :
/* This defines the delay for an initiator to check if the other device
* is polling in target mode .
* If the device starts in dual mode polling , it switches between
* initiator and target at every round .
* Because the wq is ordered and only 1 work item is executed at a time ,
* we ' ll always have one device polling as initiator and the other as
* target at some point , even if both are started in dual mode .
*/
queue_delayed_work ( wq , & dev - > poll_work , msecs_to_jiffies ( 200 ) ) ;
unlock :
mutex_unlock ( & peer - > lock ) ;
mutex_unlock ( & dev - > lock ) ;
return dev ;
}
static struct nfcsim * nfcsim_init_dev ( void )
static void nfcsim_device_free ( struct nfcsim * dev )
{
struct nfcsim * dev ;
int rc = - ENOMEM ;
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
if ( dev = = NULL )
return ERR_PTR ( - ENOMEM ) ;
mutex_init ( & dev - > lock ) ;
INIT_DELAYED_WORK ( & dev - > recv_work , nfcsim_wq_recv ) ;
INIT_DELAYED_WORK ( & dev - > poll_work , nfcsim_wq_poll ) ;
dev - > nfc_dev = nfc_allocate_device ( & nfcsim_nfc_ops ,
NFC_PROTO_NFC_DEP_MASK ,
0 , 0 ) ;
if ( ! dev - > nfc_dev )
goto error ;
nfc_digital_unregister_device ( dev - > nfc_digital_dev ) ;
nfc_set_drvdata ( dev - > nfc_dev , dev ) ;
dev - > up = false ;
rc = nfc_register_device ( dev - > nfc_dev ) ;
if ( rc )
goto free_nfc_dev ;
nfcsim_link_shutdown ( dev - > link_in ) ;
dev - > rx_delay = RX_DEFAULT_DELAY ;
return dev ;
cancel_delayed_work_sync ( & dev - > send_work ) ;
cancel_work_sync ( & dev - > recv_work ) ;
free_nfc_dev :
nfc_free_device ( dev - > nfc_dev ) ;
nfc_digital_free_device ( dev - > nfc_digital_dev ) ;
error :
kfree ( dev ) ;
return ERR_PTR ( rc ) ;
}
static void nfcsim_free_device ( struct nfcsim * dev )
{
nfc_unregister_device ( dev - > nfc_dev ) ;
nfc_free_device ( dev - > nfc_dev ) ;
kfree ( dev ) ;
}
static struct nfcsim * dev0 ;
static struct nfcsim * dev1 ;
static int __init nfcsim_init ( void )
{
struct nfcsim_link * link0 , * link1 ;
int rc ;
/* We need an ordered wq to ensure that poll_work items are executed
* one at a time .
*/
wq = alloc_ordered_workqueue ( " nfcsim " , 0 ) ;
if ( ! wq ) {
link0 = nfcsim_link_new ( ) ;
link1 = nfcsim_link_new ( ) ;
if ( ! link0 | | ! link1 ) {
rc = - ENOMEM ;
goto exit ;
goto exit_err ;
}
dev0 = nfcsim_init_ dev ( ) ;
dev0 = nfcsim_device_new ( link0 , link1 ) ;
if ( IS_ERR ( dev0 ) ) {
rc = PTR_ERR ( dev0 ) ;
goto exit ;
goto exit_err ;
}
dev1 = nfcsim_init_ dev ( ) ;
dev1 = nfcsim_device_new ( link1 , link0 ) ;
if ( IS_ERR ( dev1 ) ) {
k free( dev0 ) ;
nfcsim_device_ free( dev0 ) ;
rc = PTR_ERR ( dev1 ) ;
goto exit ;
goto exit_err ;
}
dev0 - > peer_dev = dev1 ;
dev1 - > peer_dev = dev0 ;
pr_info ( " nfcsim " NFCSIM_VERSION " initialized \n " ) ;
pr_debug ( " NFCsim " NFCSIM_VERSION " initialized \n " ) ;
return 0 ;
exit_err :
pr_err ( " Failed to initialize nfcsim driver (%d) \n " , rc ) ;
rc = 0 ;
exit :
if ( rc )
pr_err ( " Failed to initialize nfcsim driver (%d) \n " ,
rc ) ;
nfcsim_link_free ( link0 ) ;
nfcsim_link_free ( link1 ) ;
return rc ;
}
static void __exit nfcsim_exit ( void )
{
nfcsim_cleanup_dev ( dev0 , 1 ) ;
nfcsim_cleanup_dev ( dev1 , 1 ) ;
struct nfcsim_link * link0 , * link1 ;
link0 = dev0 - > link_in ;
link1 = dev0 - > link_out ;
nfcsim_free_device ( dev0 ) ;
nfcsim_free_ device ( dev1 ) ;
nfcsim_device_fre e ( dev0 ) ;
nfcsim_device_fre e ( dev1 ) ;
destroy_workqueue ( wq ) ;
nfcsim_link_free ( link0 ) ;
nfcsim_link_free ( link1 ) ;
}
module_init ( nfcsim_init ) ;