17cbe0ff3SThierry Escande /* 27cbe0ff3SThierry Escande * NFC hardware simulation driver 37cbe0ff3SThierry Escande * Copyright (c) 2013, Intel Corporation. 47cbe0ff3SThierry Escande * 57cbe0ff3SThierry Escande * This program is free software; you can redistribute it and/or modify it 67cbe0ff3SThierry Escande * under the terms and conditions of the GNU General Public License, 77cbe0ff3SThierry Escande * version 2, as published by the Free Software Foundation. 87cbe0ff3SThierry Escande * 97cbe0ff3SThierry Escande * This program is distributed in the hope it will be useful, but WITHOUT 107cbe0ff3SThierry Escande * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 117cbe0ff3SThierry Escande * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 127cbe0ff3SThierry Escande * more details. 137cbe0ff3SThierry Escande * 147cbe0ff3SThierry Escande */ 157cbe0ff3SThierry Escande 167cbe0ff3SThierry Escande #include <linux/device.h> 177cbe0ff3SThierry Escande #include <linux/kernel.h> 187cbe0ff3SThierry Escande #include <linux/module.h> 197cbe0ff3SThierry Escande #include <linux/nfc.h> 207cbe0ff3SThierry Escande #include <net/nfc/nfc.h> 21*204bddcbSThierry Escande #include <net/nfc/digital.h> 227cbe0ff3SThierry Escande 23*204bddcbSThierry Escande #define NFCSIM_ERR(d, fmt, args...) nfc_err(&d->nfc_digital_dev->nfc_dev->dev, \ 247cbe0ff3SThierry Escande "%s: " fmt, __func__, ## args) 257cbe0ff3SThierry Escande 26*204bddcbSThierry Escande #define NFCSIM_DBG(d, fmt, args...) dev_dbg(&d->nfc_digital_dev->nfc_dev->dev, \ 277cbe0ff3SThierry Escande "%s: " fmt, __func__, ## args) 287cbe0ff3SThierry Escande 29*204bddcbSThierry Escande #define NFCSIM_VERSION "0.2" 307cbe0ff3SThierry Escande 31*204bddcbSThierry Escande #define NFCSIM_MODE_NONE 0 32*204bddcbSThierry Escande #define NFCSIM_MODE_INITIATOR 1 33*204bddcbSThierry Escande #define NFCSIM_MODE_TARGET 2 347cbe0ff3SThierry Escande 35*204bddcbSThierry Escande #define NFCSIM_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC | \ 36*204bddcbSThierry Escande NFC_DIGITAL_DRV_CAPS_TG_CRC) 37a440f1aaSSaurabh Sengar 387cbe0ff3SThierry Escande struct nfcsim { 39*204bddcbSThierry Escande struct nfc_digital_dev *nfc_digital_dev; 407cbe0ff3SThierry Escande 41*204bddcbSThierry Escande struct work_struct recv_work; 42*204bddcbSThierry Escande struct delayed_work send_work; 437cbe0ff3SThierry Escande 44*204bddcbSThierry Escande struct nfcsim_link *link_in; 45*204bddcbSThierry Escande struct nfcsim_link *link_out; 467cbe0ff3SThierry Escande 47*204bddcbSThierry Escande bool up; 48*204bddcbSThierry Escande u8 mode; 49*204bddcbSThierry Escande u8 rf_tech; 507cbe0ff3SThierry Escande 51*204bddcbSThierry Escande u16 recv_timeout; 527cbe0ff3SThierry Escande 53*204bddcbSThierry Escande nfc_digital_cmd_complete_t cb; 54*204bddcbSThierry Escande void *arg; 557cbe0ff3SThierry Escande }; 567cbe0ff3SThierry Escande 57*204bddcbSThierry Escande struct nfcsim_link { 58*204bddcbSThierry Escande struct mutex lock; 597cbe0ff3SThierry Escande 60*204bddcbSThierry Escande u8 rf_tech; 61*204bddcbSThierry Escande u8 mode; 627cbe0ff3SThierry Escande 63*204bddcbSThierry Escande u8 shutdown; 64*204bddcbSThierry Escande 65*204bddcbSThierry Escande struct sk_buff *skb; 66*204bddcbSThierry Escande wait_queue_head_t recv_wait; 67*204bddcbSThierry Escande u8 cond; 68*204bddcbSThierry Escande }; 69*204bddcbSThierry Escande 70*204bddcbSThierry Escande static struct nfcsim_link *nfcsim_link_new(void) 717cbe0ff3SThierry Escande { 72*204bddcbSThierry Escande struct nfcsim_link *link; 737cbe0ff3SThierry Escande 74*204bddcbSThierry Escande link = kzalloc(sizeof(struct nfcsim_link), GFP_KERNEL); 75*204bddcbSThierry Escande if (!link) 76*204bddcbSThierry Escande return NULL; 777cbe0ff3SThierry Escande 78*204bddcbSThierry Escande mutex_init(&link->lock); 79*204bddcbSThierry Escande init_waitqueue_head(&link->recv_wait); 807cbe0ff3SThierry Escande 81*204bddcbSThierry Escande return link; 827cbe0ff3SThierry Escande } 837cbe0ff3SThierry Escande 84*204bddcbSThierry Escande static void nfcsim_link_free(struct nfcsim_link *link) 857cbe0ff3SThierry Escande { 86*204bddcbSThierry Escande dev_kfree_skb(link->skb); 87*204bddcbSThierry Escande kfree(link); 887cbe0ff3SThierry Escande } 897cbe0ff3SThierry Escande 90*204bddcbSThierry Escande static void nfcsim_link_recv_wake(struct nfcsim_link *link) 917cbe0ff3SThierry Escande { 92*204bddcbSThierry Escande link->cond = 1; 93*204bddcbSThierry Escande wake_up_interruptible(&link->recv_wait); 947cbe0ff3SThierry Escande } 957cbe0ff3SThierry Escande 96*204bddcbSThierry Escande static void nfcsim_link_set_skb(struct nfcsim_link *link, struct sk_buff *skb, 97*204bddcbSThierry Escande u8 rf_tech, u8 mode) 987cbe0ff3SThierry Escande { 99*204bddcbSThierry Escande mutex_lock(&link->lock); 1007cbe0ff3SThierry Escande 101*204bddcbSThierry Escande dev_kfree_skb(link->skb); 102*204bddcbSThierry Escande link->skb = skb; 103*204bddcbSThierry Escande link->rf_tech = rf_tech; 104*204bddcbSThierry Escande link->mode = mode; 1057cbe0ff3SThierry Escande 106*204bddcbSThierry Escande mutex_unlock(&link->lock); 1077cbe0ff3SThierry Escande } 1087cbe0ff3SThierry Escande 109*204bddcbSThierry Escande static void nfcsim_link_recv_cancel(struct nfcsim_link *link) 110*204bddcbSThierry Escande { 111*204bddcbSThierry Escande mutex_lock(&link->lock); 112*204bddcbSThierry Escande 113*204bddcbSThierry Escande link->mode = NFCSIM_MODE_NONE; 114*204bddcbSThierry Escande 115*204bddcbSThierry Escande mutex_unlock(&link->lock); 116*204bddcbSThierry Escande 117*204bddcbSThierry Escande nfcsim_link_recv_wake(link); 118*204bddcbSThierry Escande } 119*204bddcbSThierry Escande 120*204bddcbSThierry Escande static void nfcsim_link_shutdown(struct nfcsim_link *link) 121*204bddcbSThierry Escande { 122*204bddcbSThierry Escande mutex_lock(&link->lock); 123*204bddcbSThierry Escande 124*204bddcbSThierry Escande link->shutdown = 1; 125*204bddcbSThierry Escande link->mode = NFCSIM_MODE_NONE; 126*204bddcbSThierry Escande 127*204bddcbSThierry Escande mutex_unlock(&link->lock); 128*204bddcbSThierry Escande 129*204bddcbSThierry Escande nfcsim_link_recv_wake(link); 130*204bddcbSThierry Escande } 131*204bddcbSThierry Escande 132*204bddcbSThierry Escande static struct sk_buff *nfcsim_link_recv_skb(struct nfcsim_link *link, 133*204bddcbSThierry Escande int timeout, u8 rf_tech, u8 mode) 1347cbe0ff3SThierry Escande { 1357cbe0ff3SThierry Escande int rc; 136*204bddcbSThierry Escande struct sk_buff *skb; 1377cbe0ff3SThierry Escande 138*204bddcbSThierry Escande rc = wait_event_interruptible_timeout(link->recv_wait, 139*204bddcbSThierry Escande link->cond, 140*204bddcbSThierry Escande msecs_to_jiffies(timeout)); 1417cbe0ff3SThierry Escande 142*204bddcbSThierry Escande mutex_lock(&link->lock); 1437cbe0ff3SThierry Escande 144*204bddcbSThierry Escande skb = link->skb; 145*204bddcbSThierry Escande link->skb = NULL; 1467cbe0ff3SThierry Escande 147*204bddcbSThierry Escande if (!rc) { 148*204bddcbSThierry Escande rc = -ETIMEDOUT; 149*204bddcbSThierry Escande goto done; 150*204bddcbSThierry Escande } 1517cbe0ff3SThierry Escande 152*204bddcbSThierry Escande if (!skb || link->rf_tech != rf_tech || link->mode == mode) { 153*204bddcbSThierry Escande rc = -EINVAL; 154*204bddcbSThierry Escande goto done; 155*204bddcbSThierry Escande } 156*204bddcbSThierry Escande 157*204bddcbSThierry Escande if (link->shutdown) { 158*204bddcbSThierry Escande rc = -ENODEV; 159*204bddcbSThierry Escande goto done; 160*204bddcbSThierry Escande } 161*204bddcbSThierry Escande 162*204bddcbSThierry Escande done: 163*204bddcbSThierry Escande mutex_unlock(&link->lock); 164*204bddcbSThierry Escande 165*204bddcbSThierry Escande if (rc < 0) { 166*204bddcbSThierry Escande dev_kfree_skb(skb); 167*204bddcbSThierry Escande skb = ERR_PTR(rc); 168*204bddcbSThierry Escande } 169*204bddcbSThierry Escande 170*204bddcbSThierry Escande link->cond = 0; 171*204bddcbSThierry Escande 172*204bddcbSThierry Escande return skb; 173*204bddcbSThierry Escande } 174*204bddcbSThierry Escande 175*204bddcbSThierry Escande static void nfcsim_send_wq(struct work_struct *work) 176*204bddcbSThierry Escande { 177*204bddcbSThierry Escande struct nfcsim *dev = container_of(work, struct nfcsim, send_work.work); 178*204bddcbSThierry Escande 179*204bddcbSThierry Escande /* 180*204bddcbSThierry Escande * To effectively send data, the device just wake up its link_out which 181*204bddcbSThierry Escande * is the link_in of the peer device. The exchanged skb has already been 182*204bddcbSThierry Escande * stored in the dev->link_out through nfcsim_link_set_skb(). 183*204bddcbSThierry Escande */ 184*204bddcbSThierry Escande nfcsim_link_recv_wake(dev->link_out); 185*204bddcbSThierry Escande } 186*204bddcbSThierry Escande 187*204bddcbSThierry Escande static void nfcsim_recv_wq(struct work_struct *work) 188*204bddcbSThierry Escande { 189*204bddcbSThierry Escande struct nfcsim *dev = container_of(work, struct nfcsim, recv_work); 190*204bddcbSThierry Escande struct sk_buff *skb; 191*204bddcbSThierry Escande 192*204bddcbSThierry Escande skb = nfcsim_link_recv_skb(dev->link_in, dev->recv_timeout, 193*204bddcbSThierry Escande dev->rf_tech, dev->mode); 194*204bddcbSThierry Escande 195*204bddcbSThierry Escande if (!dev->up) { 196*204bddcbSThierry Escande NFCSIM_ERR(dev, "Device is down\n"); 197*204bddcbSThierry Escande 198*204bddcbSThierry Escande if (!IS_ERR(skb)) 199*204bddcbSThierry Escande dev_kfree_skb(skb); 200*204bddcbSThierry Escande 201*204bddcbSThierry Escande skb = ERR_PTR(-ENODEV); 202*204bddcbSThierry Escande } 203*204bddcbSThierry Escande 204*204bddcbSThierry Escande dev->cb(dev->nfc_digital_dev, dev->arg, skb); 205*204bddcbSThierry Escande } 206*204bddcbSThierry Escande 207*204bddcbSThierry Escande static int nfcsim_send(struct nfc_digital_dev *ddev, struct sk_buff *skb, 208*204bddcbSThierry Escande u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) 209*204bddcbSThierry Escande { 210*204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 211*204bddcbSThierry Escande u8 delay; 212*204bddcbSThierry Escande 213*204bddcbSThierry Escande if (!dev->up) { 214*204bddcbSThierry Escande NFCSIM_ERR(dev, "Device is down\n"); 215*204bddcbSThierry Escande return -ENODEV; 216*204bddcbSThierry Escande } 217*204bddcbSThierry Escande 218*204bddcbSThierry Escande dev->recv_timeout = timeout; 219*204bddcbSThierry Escande dev->cb = cb; 220*204bddcbSThierry Escande dev->arg = arg; 221*204bddcbSThierry Escande 222*204bddcbSThierry Escande schedule_work(&dev->recv_work); 223*204bddcbSThierry Escande 224*204bddcbSThierry Escande if (skb) { 225*204bddcbSThierry Escande nfcsim_link_set_skb(dev->link_out, skb, dev->rf_tech, 226*204bddcbSThierry Escande dev->mode); 227*204bddcbSThierry Escande 228*204bddcbSThierry Escande /* Add random delay (between 3 and 10 ms) before sending data */ 229*204bddcbSThierry Escande get_random_bytes(&delay, 1); 230*204bddcbSThierry Escande delay = 3 + (delay & 0x07); 231*204bddcbSThierry Escande 232*204bddcbSThierry Escande schedule_delayed_work(&dev->send_work, msecs_to_jiffies(delay)); 233*204bddcbSThierry Escande } 234*204bddcbSThierry Escande 235*204bddcbSThierry Escande return 0; 236*204bddcbSThierry Escande } 237*204bddcbSThierry Escande 238*204bddcbSThierry Escande static void nfcsim_abort_cmd(struct nfc_digital_dev *ddev) 239*204bddcbSThierry Escande { 240*204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 241*204bddcbSThierry Escande 242*204bddcbSThierry Escande nfcsim_link_recv_cancel(dev->link_in); 243*204bddcbSThierry Escande } 244*204bddcbSThierry Escande 245*204bddcbSThierry Escande static int nfcsim_switch_rf(struct nfc_digital_dev *ddev, bool on) 246*204bddcbSThierry Escande { 247*204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 248*204bddcbSThierry Escande 249*204bddcbSThierry Escande dev->up = on; 250*204bddcbSThierry Escande 251*204bddcbSThierry Escande return 0; 252*204bddcbSThierry Escande } 253*204bddcbSThierry Escande 254*204bddcbSThierry Escande static int nfcsim_in_configure_hw(struct nfc_digital_dev *ddev, 255*204bddcbSThierry Escande int type, int param) 256*204bddcbSThierry Escande { 257*204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 258*204bddcbSThierry Escande 259*204bddcbSThierry Escande switch (type) { 260*204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_RF_TECH: 261*204bddcbSThierry Escande dev->up = true; 262*204bddcbSThierry Escande dev->mode = NFCSIM_MODE_INITIATOR; 263*204bddcbSThierry Escande dev->rf_tech = param; 264*204bddcbSThierry Escande break; 265*204bddcbSThierry Escande 266*204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_FRAMING: 267*204bddcbSThierry Escande break; 268*204bddcbSThierry Escande 269*204bddcbSThierry Escande default: 270*204bddcbSThierry Escande NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type); 2717cbe0ff3SThierry Escande return -EINVAL; 2727cbe0ff3SThierry Escande } 2737cbe0ff3SThierry Escande 274*204bddcbSThierry Escande return 0; 2757cbe0ff3SThierry Escande } 2767cbe0ff3SThierry Escande 277*204bddcbSThierry Escande static int nfcsim_in_send_cmd(struct nfc_digital_dev *ddev, 278*204bddcbSThierry Escande struct sk_buff *skb, u16 timeout, 279*204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 2807cbe0ff3SThierry Escande { 281*204bddcbSThierry Escande return nfcsim_send(ddev, skb, timeout, cb, arg); 282*204bddcbSThierry Escande } 2837cbe0ff3SThierry Escande 284*204bddcbSThierry Escande static int nfcsim_tg_configure_hw(struct nfc_digital_dev *ddev, 285*204bddcbSThierry Escande int type, int param) 286*204bddcbSThierry Escande { 287*204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 2887cbe0ff3SThierry Escande 289*204bddcbSThierry Escande switch (type) { 290*204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_RF_TECH: 291*204bddcbSThierry Escande dev->up = true; 292*204bddcbSThierry Escande dev->mode = NFCSIM_MODE_TARGET; 293*204bddcbSThierry Escande dev->rf_tech = param; 294*204bddcbSThierry Escande break; 295*204bddcbSThierry Escande 296*204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_FRAMING: 297*204bddcbSThierry Escande break; 298*204bddcbSThierry Escande 299*204bddcbSThierry Escande default: 300*204bddcbSThierry Escande NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type); 301*204bddcbSThierry Escande return -EINVAL; 302*204bddcbSThierry Escande } 3037cbe0ff3SThierry Escande 3047cbe0ff3SThierry Escande return 0; 3057cbe0ff3SThierry Escande } 3067cbe0ff3SThierry Escande 307*204bddcbSThierry Escande static int nfcsim_tg_send_cmd(struct nfc_digital_dev *ddev, 308*204bddcbSThierry Escande struct sk_buff *skb, u16 timeout, 309*204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 3107cbe0ff3SThierry Escande { 311*204bddcbSThierry Escande return nfcsim_send(ddev, skb, timeout, cb, arg); 3127cbe0ff3SThierry Escande } 3137cbe0ff3SThierry Escande 314*204bddcbSThierry Escande static int nfcsim_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, 315*204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 3167cbe0ff3SThierry Escande { 317*204bddcbSThierry Escande return nfcsim_send(ddev, NULL, timeout, cb, arg); 3187cbe0ff3SThierry Escande } 3197cbe0ff3SThierry Escande 320*204bddcbSThierry Escande static struct nfc_digital_ops nfcsim_digital_ops = { 321*204bddcbSThierry Escande .in_configure_hw = nfcsim_in_configure_hw, 322*204bddcbSThierry Escande .in_send_cmd = nfcsim_in_send_cmd, 3237cbe0ff3SThierry Escande 324*204bddcbSThierry Escande .tg_listen = nfcsim_tg_listen, 325*204bddcbSThierry Escande .tg_configure_hw = nfcsim_tg_configure_hw, 326*204bddcbSThierry Escande .tg_send_cmd = nfcsim_tg_send_cmd, 3277cbe0ff3SThierry Escande 328*204bddcbSThierry Escande .abort_cmd = nfcsim_abort_cmd, 329*204bddcbSThierry Escande .switch_rf = nfcsim_switch_rf, 3307cbe0ff3SThierry Escande }; 3317cbe0ff3SThierry Escande 332*204bddcbSThierry Escande static struct nfcsim *nfcsim_device_new(struct nfcsim_link *link_in, 333*204bddcbSThierry Escande struct nfcsim_link *link_out) 3347cbe0ff3SThierry Escande { 3357cbe0ff3SThierry Escande struct nfcsim *dev; 336*204bddcbSThierry Escande int rc; 3377cbe0ff3SThierry Escande 338*204bddcbSThierry Escande dev = kzalloc(sizeof(struct nfcsim), GFP_KERNEL); 339*204bddcbSThierry Escande if (!dev) 3407cbe0ff3SThierry Escande return ERR_PTR(-ENOMEM); 3417cbe0ff3SThierry Escande 342*204bddcbSThierry Escande INIT_DELAYED_WORK(&dev->send_work, nfcsim_send_wq); 343*204bddcbSThierry Escande INIT_WORK(&dev->recv_work, nfcsim_recv_wq); 3447cbe0ff3SThierry Escande 345*204bddcbSThierry Escande dev->nfc_digital_dev = 346*204bddcbSThierry Escande nfc_digital_allocate_device(&nfcsim_digital_ops, 3477cbe0ff3SThierry Escande NFC_PROTO_NFC_DEP_MASK, 348*204bddcbSThierry Escande NFCSIM_CAPABILITIES, 3497cbe0ff3SThierry Escande 0, 0); 350*204bddcbSThierry Escande if (!dev->nfc_digital_dev) { 351*204bddcbSThierry Escande kfree(dev); 352*204bddcbSThierry Escande return ERR_PTR(-ENOMEM); 353*204bddcbSThierry Escande } 3547cbe0ff3SThierry Escande 355*204bddcbSThierry Escande nfc_digital_set_drvdata(dev->nfc_digital_dev, dev); 3567cbe0ff3SThierry Escande 357*204bddcbSThierry Escande dev->link_in = link_in; 358*204bddcbSThierry Escande dev->link_out = link_out; 3597cbe0ff3SThierry Escande 360*204bddcbSThierry Escande rc = nfc_digital_register_device(dev->nfc_digital_dev); 361*204bddcbSThierry Escande if (rc) { 362*204bddcbSThierry Escande pr_err("Could not register digital device (%d)\n", rc); 363*204bddcbSThierry Escande nfc_digital_free_device(dev->nfc_digital_dev); 3647cbe0ff3SThierry Escande kfree(dev); 3657cbe0ff3SThierry Escande 3667cbe0ff3SThierry Escande return ERR_PTR(rc); 3677cbe0ff3SThierry Escande } 3687cbe0ff3SThierry Escande 369*204bddcbSThierry Escande return dev; 370*204bddcbSThierry Escande } 3717cbe0ff3SThierry Escande 372*204bddcbSThierry Escande static void nfcsim_device_free(struct nfcsim *dev) 373*204bddcbSThierry Escande { 374*204bddcbSThierry Escande nfc_digital_unregister_device(dev->nfc_digital_dev); 375*204bddcbSThierry Escande 376*204bddcbSThierry Escande dev->up = false; 377*204bddcbSThierry Escande 378*204bddcbSThierry Escande nfcsim_link_shutdown(dev->link_in); 379*204bddcbSThierry Escande 380*204bddcbSThierry Escande cancel_delayed_work_sync(&dev->send_work); 381*204bddcbSThierry Escande cancel_work_sync(&dev->recv_work); 382*204bddcbSThierry Escande 383*204bddcbSThierry Escande nfc_digital_free_device(dev->nfc_digital_dev); 3847cbe0ff3SThierry Escande 3857cbe0ff3SThierry Escande kfree(dev); 3867cbe0ff3SThierry Escande } 3877cbe0ff3SThierry Escande 388*204bddcbSThierry Escande static struct nfcsim *dev0; 389*204bddcbSThierry Escande static struct nfcsim *dev1; 390*204bddcbSThierry Escande 39140dac370SThierry Escande static int __init nfcsim_init(void) 3927cbe0ff3SThierry Escande { 393*204bddcbSThierry Escande struct nfcsim_link *link0, *link1; 3947cbe0ff3SThierry Escande int rc; 3957cbe0ff3SThierry Escande 396*204bddcbSThierry Escande link0 = nfcsim_link_new(); 397*204bddcbSThierry Escande link1 = nfcsim_link_new(); 398*204bddcbSThierry Escande if (!link0 || !link1) { 3997cbe0ff3SThierry Escande rc = -ENOMEM; 400*204bddcbSThierry Escande goto exit_err; 4017cbe0ff3SThierry Escande } 4027cbe0ff3SThierry Escande 403*204bddcbSThierry Escande dev0 = nfcsim_device_new(link0, link1); 4047cbe0ff3SThierry Escande if (IS_ERR(dev0)) { 4057cbe0ff3SThierry Escande rc = PTR_ERR(dev0); 406*204bddcbSThierry Escande goto exit_err; 4077cbe0ff3SThierry Escande } 4087cbe0ff3SThierry Escande 409*204bddcbSThierry Escande dev1 = nfcsim_device_new(link1, link0); 4107cbe0ff3SThierry Escande if (IS_ERR(dev1)) { 411*204bddcbSThierry Escande nfcsim_device_free(dev0); 4127cbe0ff3SThierry Escande 4137cbe0ff3SThierry Escande rc = PTR_ERR(dev1); 414*204bddcbSThierry Escande goto exit_err; 4157cbe0ff3SThierry Escande } 4167cbe0ff3SThierry Escande 417*204bddcbSThierry Escande pr_info("nfcsim " NFCSIM_VERSION " initialized\n"); 4187cbe0ff3SThierry Escande 419*204bddcbSThierry Escande return 0; 4207cbe0ff3SThierry Escande 421*204bddcbSThierry Escande exit_err: 422*204bddcbSThierry Escande pr_err("Failed to initialize nfcsim driver (%d)\n", rc); 423*204bddcbSThierry Escande 424*204bddcbSThierry Escande nfcsim_link_free(link0); 425*204bddcbSThierry Escande nfcsim_link_free(link1); 4267cbe0ff3SThierry Escande 4277cbe0ff3SThierry Escande return rc; 4287cbe0ff3SThierry Escande } 4297cbe0ff3SThierry Escande 43040dac370SThierry Escande static void __exit nfcsim_exit(void) 4317cbe0ff3SThierry Escande { 432*204bddcbSThierry Escande struct nfcsim_link *link0, *link1; 4337cbe0ff3SThierry Escande 434*204bddcbSThierry Escande link0 = dev0->link_in; 435*204bddcbSThierry Escande link1 = dev0->link_out; 4367cbe0ff3SThierry Escande 437*204bddcbSThierry Escande nfcsim_device_free(dev0); 438*204bddcbSThierry Escande nfcsim_device_free(dev1); 439*204bddcbSThierry Escande 440*204bddcbSThierry Escande nfcsim_link_free(link0); 441*204bddcbSThierry Escande nfcsim_link_free(link1); 4427cbe0ff3SThierry Escande } 4437cbe0ff3SThierry Escande 4447cbe0ff3SThierry Escande module_init(nfcsim_init); 4457cbe0ff3SThierry Escande module_exit(nfcsim_exit); 4467cbe0ff3SThierry Escande 4477cbe0ff3SThierry Escande MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION); 4487cbe0ff3SThierry Escande MODULE_VERSION(NFCSIM_VERSION); 4497cbe0ff3SThierry Escande MODULE_LICENSE("GPL"); 450