12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 27cbe0ff3SThierry Escande /* 37cbe0ff3SThierry Escande * NFC hardware simulation driver 47cbe0ff3SThierry Escande * Copyright (c) 2013, Intel Corporation. 57cbe0ff3SThierry Escande */ 67cbe0ff3SThierry Escande 77cbe0ff3SThierry Escande #include <linux/device.h> 87cbe0ff3SThierry Escande #include <linux/kernel.h> 97cbe0ff3SThierry Escande #include <linux/module.h> 10f9ac6273SThierry Escande #include <linux/ctype.h> 11f9ac6273SThierry Escande #include <linux/debugfs.h> 127cbe0ff3SThierry Escande #include <linux/nfc.h> 137cbe0ff3SThierry Escande #include <net/nfc/nfc.h> 14204bddcbSThierry Escande #include <net/nfc/digital.h> 157cbe0ff3SThierry Escande 16204bddcbSThierry Escande #define NFCSIM_ERR(d, fmt, args...) nfc_err(&d->nfc_digital_dev->nfc_dev->dev, \ 177cbe0ff3SThierry Escande "%s: " fmt, __func__, ## args) 187cbe0ff3SThierry Escande 19204bddcbSThierry Escande #define NFCSIM_DBG(d, fmt, args...) dev_dbg(&d->nfc_digital_dev->nfc_dev->dev, \ 207cbe0ff3SThierry Escande "%s: " fmt, __func__, ## args) 217cbe0ff3SThierry Escande 22204bddcbSThierry Escande #define NFCSIM_VERSION "0.2" 237cbe0ff3SThierry Escande 24204bddcbSThierry Escande #define NFCSIM_MODE_NONE 0 25204bddcbSThierry Escande #define NFCSIM_MODE_INITIATOR 1 26204bddcbSThierry Escande #define NFCSIM_MODE_TARGET 2 277cbe0ff3SThierry Escande 28204bddcbSThierry Escande #define NFCSIM_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC | \ 29204bddcbSThierry Escande NFC_DIGITAL_DRV_CAPS_TG_CRC) 30a440f1aaSSaurabh Sengar 317cbe0ff3SThierry Escande struct nfcsim { 32204bddcbSThierry Escande struct nfc_digital_dev *nfc_digital_dev; 337cbe0ff3SThierry Escande 34204bddcbSThierry Escande struct work_struct recv_work; 35204bddcbSThierry Escande struct delayed_work send_work; 367cbe0ff3SThierry Escande 37204bddcbSThierry Escande struct nfcsim_link *link_in; 38204bddcbSThierry Escande struct nfcsim_link *link_out; 397cbe0ff3SThierry Escande 40204bddcbSThierry Escande bool up; 41204bddcbSThierry Escande u8 mode; 42204bddcbSThierry Escande u8 rf_tech; 437cbe0ff3SThierry Escande 44204bddcbSThierry Escande u16 recv_timeout; 457cbe0ff3SThierry Escande 46204bddcbSThierry Escande nfc_digital_cmd_complete_t cb; 47204bddcbSThierry Escande void *arg; 482a0fe4feSThierry Escande 492a0fe4feSThierry Escande u8 dropframe; 507cbe0ff3SThierry Escande }; 517cbe0ff3SThierry Escande 52204bddcbSThierry Escande struct nfcsim_link { 53204bddcbSThierry Escande struct mutex lock; 547cbe0ff3SThierry Escande 55204bddcbSThierry Escande u8 rf_tech; 56204bddcbSThierry Escande u8 mode; 577cbe0ff3SThierry Escande 58204bddcbSThierry Escande u8 shutdown; 59204bddcbSThierry Escande 60204bddcbSThierry Escande struct sk_buff *skb; 61204bddcbSThierry Escande wait_queue_head_t recv_wait; 62204bddcbSThierry Escande u8 cond; 63204bddcbSThierry Escande }; 64204bddcbSThierry Escande 65204bddcbSThierry Escande static struct nfcsim_link *nfcsim_link_new(void) 667cbe0ff3SThierry Escande { 67204bddcbSThierry Escande struct nfcsim_link *link; 687cbe0ff3SThierry Escande 69204bddcbSThierry Escande link = kzalloc(sizeof(struct nfcsim_link), GFP_KERNEL); 70204bddcbSThierry Escande if (!link) 71204bddcbSThierry Escande return NULL; 727cbe0ff3SThierry Escande 73204bddcbSThierry Escande mutex_init(&link->lock); 74204bddcbSThierry Escande init_waitqueue_head(&link->recv_wait); 757cbe0ff3SThierry Escande 76204bddcbSThierry Escande return link; 777cbe0ff3SThierry Escande } 787cbe0ff3SThierry Escande 79204bddcbSThierry Escande static void nfcsim_link_free(struct nfcsim_link *link) 807cbe0ff3SThierry Escande { 81204bddcbSThierry Escande dev_kfree_skb(link->skb); 82204bddcbSThierry Escande kfree(link); 837cbe0ff3SThierry Escande } 847cbe0ff3SThierry Escande 85204bddcbSThierry Escande static void nfcsim_link_recv_wake(struct nfcsim_link *link) 867cbe0ff3SThierry Escande { 87204bddcbSThierry Escande link->cond = 1; 88204bddcbSThierry Escande wake_up_interruptible(&link->recv_wait); 897cbe0ff3SThierry Escande } 907cbe0ff3SThierry Escande 91204bddcbSThierry Escande static void nfcsim_link_set_skb(struct nfcsim_link *link, struct sk_buff *skb, 92204bddcbSThierry Escande u8 rf_tech, u8 mode) 937cbe0ff3SThierry Escande { 94204bddcbSThierry Escande mutex_lock(&link->lock); 957cbe0ff3SThierry Escande 96204bddcbSThierry Escande dev_kfree_skb(link->skb); 97204bddcbSThierry Escande link->skb = skb; 98204bddcbSThierry Escande link->rf_tech = rf_tech; 99204bddcbSThierry Escande link->mode = mode; 1007cbe0ff3SThierry Escande 101204bddcbSThierry Escande mutex_unlock(&link->lock); 1027cbe0ff3SThierry Escande } 1037cbe0ff3SThierry Escande 104204bddcbSThierry Escande static void nfcsim_link_recv_cancel(struct nfcsim_link *link) 105204bddcbSThierry Escande { 106204bddcbSThierry Escande mutex_lock(&link->lock); 107204bddcbSThierry Escande 108204bddcbSThierry Escande link->mode = NFCSIM_MODE_NONE; 109204bddcbSThierry Escande 110204bddcbSThierry Escande mutex_unlock(&link->lock); 111204bddcbSThierry Escande 112204bddcbSThierry Escande nfcsim_link_recv_wake(link); 113204bddcbSThierry Escande } 114204bddcbSThierry Escande 115204bddcbSThierry Escande static void nfcsim_link_shutdown(struct nfcsim_link *link) 116204bddcbSThierry Escande { 117204bddcbSThierry Escande mutex_lock(&link->lock); 118204bddcbSThierry Escande 119204bddcbSThierry Escande link->shutdown = 1; 120204bddcbSThierry Escande link->mode = NFCSIM_MODE_NONE; 121204bddcbSThierry Escande 122204bddcbSThierry Escande mutex_unlock(&link->lock); 123204bddcbSThierry Escande 124204bddcbSThierry Escande nfcsim_link_recv_wake(link); 125204bddcbSThierry Escande } 126204bddcbSThierry Escande 127204bddcbSThierry Escande static struct sk_buff *nfcsim_link_recv_skb(struct nfcsim_link *link, 128204bddcbSThierry Escande int timeout, u8 rf_tech, u8 mode) 1297cbe0ff3SThierry Escande { 1307cbe0ff3SThierry Escande int rc; 131204bddcbSThierry Escande struct sk_buff *skb; 1327cbe0ff3SThierry Escande 133204bddcbSThierry Escande rc = wait_event_interruptible_timeout(link->recv_wait, 134204bddcbSThierry Escande link->cond, 135204bddcbSThierry Escande msecs_to_jiffies(timeout)); 1367cbe0ff3SThierry Escande 137204bddcbSThierry Escande mutex_lock(&link->lock); 1387cbe0ff3SThierry Escande 139204bddcbSThierry Escande skb = link->skb; 140204bddcbSThierry Escande link->skb = NULL; 1417cbe0ff3SThierry Escande 142204bddcbSThierry Escande if (!rc) { 143204bddcbSThierry Escande rc = -ETIMEDOUT; 144204bddcbSThierry Escande goto done; 145204bddcbSThierry Escande } 1467cbe0ff3SThierry Escande 147204bddcbSThierry Escande if (!skb || link->rf_tech != rf_tech || link->mode == mode) { 148204bddcbSThierry Escande rc = -EINVAL; 149204bddcbSThierry Escande goto done; 150204bddcbSThierry Escande } 151204bddcbSThierry Escande 152204bddcbSThierry Escande if (link->shutdown) { 153204bddcbSThierry Escande rc = -ENODEV; 154204bddcbSThierry Escande goto done; 155204bddcbSThierry Escande } 156204bddcbSThierry Escande 157204bddcbSThierry Escande done: 158204bddcbSThierry Escande mutex_unlock(&link->lock); 159204bddcbSThierry Escande 160204bddcbSThierry Escande if (rc < 0) { 161204bddcbSThierry Escande dev_kfree_skb(skb); 162204bddcbSThierry Escande skb = ERR_PTR(rc); 163204bddcbSThierry Escande } 164204bddcbSThierry Escande 165204bddcbSThierry Escande link->cond = 0; 166204bddcbSThierry Escande 167204bddcbSThierry Escande return skb; 168204bddcbSThierry Escande } 169204bddcbSThierry Escande 170204bddcbSThierry Escande static void nfcsim_send_wq(struct work_struct *work) 171204bddcbSThierry Escande { 172204bddcbSThierry Escande struct nfcsim *dev = container_of(work, struct nfcsim, send_work.work); 173204bddcbSThierry Escande 174204bddcbSThierry Escande /* 175204bddcbSThierry Escande * To effectively send data, the device just wake up its link_out which 176204bddcbSThierry Escande * is the link_in of the peer device. The exchanged skb has already been 177204bddcbSThierry Escande * stored in the dev->link_out through nfcsim_link_set_skb(). 178204bddcbSThierry Escande */ 179204bddcbSThierry Escande nfcsim_link_recv_wake(dev->link_out); 180204bddcbSThierry Escande } 181204bddcbSThierry Escande 182204bddcbSThierry Escande static void nfcsim_recv_wq(struct work_struct *work) 183204bddcbSThierry Escande { 184204bddcbSThierry Escande struct nfcsim *dev = container_of(work, struct nfcsim, recv_work); 185204bddcbSThierry Escande struct sk_buff *skb; 186204bddcbSThierry Escande 187204bddcbSThierry Escande skb = nfcsim_link_recv_skb(dev->link_in, dev->recv_timeout, 188204bddcbSThierry Escande dev->rf_tech, dev->mode); 189204bddcbSThierry Escande 190204bddcbSThierry Escande if (!dev->up) { 191204bddcbSThierry Escande NFCSIM_ERR(dev, "Device is down\n"); 192204bddcbSThierry Escande 193204bddcbSThierry Escande if (!IS_ERR(skb)) 194204bddcbSThierry Escande dev_kfree_skb(skb); 195204bddcbSThierry Escande 196204bddcbSThierry Escande skb = ERR_PTR(-ENODEV); 197204bddcbSThierry Escande } 198204bddcbSThierry Escande 199204bddcbSThierry Escande dev->cb(dev->nfc_digital_dev, dev->arg, skb); 200204bddcbSThierry Escande } 201204bddcbSThierry Escande 202204bddcbSThierry Escande static int nfcsim_send(struct nfc_digital_dev *ddev, struct sk_buff *skb, 203204bddcbSThierry Escande u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) 204204bddcbSThierry Escande { 205204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 206204bddcbSThierry Escande u8 delay; 207204bddcbSThierry Escande 208204bddcbSThierry Escande if (!dev->up) { 209204bddcbSThierry Escande NFCSIM_ERR(dev, "Device is down\n"); 210204bddcbSThierry Escande return -ENODEV; 211204bddcbSThierry Escande } 212204bddcbSThierry Escande 213204bddcbSThierry Escande dev->recv_timeout = timeout; 214204bddcbSThierry Escande dev->cb = cb; 215204bddcbSThierry Escande dev->arg = arg; 216204bddcbSThierry Escande 217204bddcbSThierry Escande schedule_work(&dev->recv_work); 218204bddcbSThierry Escande 2192a0fe4feSThierry Escande if (dev->dropframe) { 2202a0fe4feSThierry Escande NFCSIM_DBG(dev, "dropping frame (out of %d)\n", dev->dropframe); 2212a0fe4feSThierry Escande dev_kfree_skb(skb); 2222a0fe4feSThierry Escande dev->dropframe--; 2232a0fe4feSThierry Escande 2242a0fe4feSThierry Escande return 0; 2252a0fe4feSThierry Escande } 2262a0fe4feSThierry Escande 227204bddcbSThierry Escande if (skb) { 228204bddcbSThierry Escande nfcsim_link_set_skb(dev->link_out, skb, dev->rf_tech, 229204bddcbSThierry Escande dev->mode); 230204bddcbSThierry Escande 231204bddcbSThierry Escande /* Add random delay (between 3 and 10 ms) before sending data */ 232204bddcbSThierry Escande get_random_bytes(&delay, 1); 233204bddcbSThierry Escande delay = 3 + (delay & 0x07); 234204bddcbSThierry Escande 235204bddcbSThierry Escande schedule_delayed_work(&dev->send_work, msecs_to_jiffies(delay)); 236204bddcbSThierry Escande } 237204bddcbSThierry Escande 238204bddcbSThierry Escande return 0; 239204bddcbSThierry Escande } 240204bddcbSThierry Escande 241204bddcbSThierry Escande static void nfcsim_abort_cmd(struct nfc_digital_dev *ddev) 242204bddcbSThierry Escande { 243204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 244204bddcbSThierry Escande 245204bddcbSThierry Escande nfcsim_link_recv_cancel(dev->link_in); 246204bddcbSThierry Escande } 247204bddcbSThierry Escande 248204bddcbSThierry Escande static int nfcsim_switch_rf(struct nfc_digital_dev *ddev, bool on) 249204bddcbSThierry Escande { 250204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 251204bddcbSThierry Escande 252204bddcbSThierry Escande dev->up = on; 253204bddcbSThierry Escande 254204bddcbSThierry Escande return 0; 255204bddcbSThierry Escande } 256204bddcbSThierry Escande 257204bddcbSThierry Escande static int nfcsim_in_configure_hw(struct nfc_digital_dev *ddev, 258204bddcbSThierry Escande int type, int param) 259204bddcbSThierry Escande { 260204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 261204bddcbSThierry Escande 262204bddcbSThierry Escande switch (type) { 263204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_RF_TECH: 264204bddcbSThierry Escande dev->up = true; 265204bddcbSThierry Escande dev->mode = NFCSIM_MODE_INITIATOR; 266204bddcbSThierry Escande dev->rf_tech = param; 267204bddcbSThierry Escande break; 268204bddcbSThierry Escande 269204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_FRAMING: 270204bddcbSThierry Escande break; 271204bddcbSThierry Escande 272204bddcbSThierry Escande default: 273204bddcbSThierry Escande NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type); 2747cbe0ff3SThierry Escande return -EINVAL; 2757cbe0ff3SThierry Escande } 2767cbe0ff3SThierry Escande 277204bddcbSThierry Escande return 0; 2787cbe0ff3SThierry Escande } 2797cbe0ff3SThierry Escande 280204bddcbSThierry Escande static int nfcsim_in_send_cmd(struct nfc_digital_dev *ddev, 281204bddcbSThierry Escande struct sk_buff *skb, u16 timeout, 282204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 2837cbe0ff3SThierry Escande { 284204bddcbSThierry Escande return nfcsim_send(ddev, skb, timeout, cb, arg); 285204bddcbSThierry Escande } 2867cbe0ff3SThierry Escande 287204bddcbSThierry Escande static int nfcsim_tg_configure_hw(struct nfc_digital_dev *ddev, 288204bddcbSThierry Escande int type, int param) 289204bddcbSThierry Escande { 290204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 2917cbe0ff3SThierry Escande 292204bddcbSThierry Escande switch (type) { 293204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_RF_TECH: 294204bddcbSThierry Escande dev->up = true; 295204bddcbSThierry Escande dev->mode = NFCSIM_MODE_TARGET; 296204bddcbSThierry Escande dev->rf_tech = param; 297204bddcbSThierry Escande break; 298204bddcbSThierry Escande 299204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_FRAMING: 300204bddcbSThierry Escande break; 301204bddcbSThierry Escande 302204bddcbSThierry Escande default: 303204bddcbSThierry Escande NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type); 304204bddcbSThierry Escande return -EINVAL; 305204bddcbSThierry Escande } 3067cbe0ff3SThierry Escande 3077cbe0ff3SThierry Escande return 0; 3087cbe0ff3SThierry Escande } 3097cbe0ff3SThierry Escande 310204bddcbSThierry Escande static int nfcsim_tg_send_cmd(struct nfc_digital_dev *ddev, 311204bddcbSThierry Escande struct sk_buff *skb, u16 timeout, 312204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 3137cbe0ff3SThierry Escande { 314204bddcbSThierry Escande return nfcsim_send(ddev, skb, timeout, cb, arg); 3157cbe0ff3SThierry Escande } 3167cbe0ff3SThierry Escande 317204bddcbSThierry Escande static int nfcsim_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, 318204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 3197cbe0ff3SThierry Escande { 320204bddcbSThierry Escande return nfcsim_send(ddev, NULL, timeout, cb, arg); 3217cbe0ff3SThierry Escande } 3227cbe0ff3SThierry Escande 323*7186aac9SKrzysztof Kozlowski static const struct nfc_digital_ops nfcsim_digital_ops = { 324204bddcbSThierry Escande .in_configure_hw = nfcsim_in_configure_hw, 325204bddcbSThierry Escande .in_send_cmd = nfcsim_in_send_cmd, 3267cbe0ff3SThierry Escande 327204bddcbSThierry Escande .tg_listen = nfcsim_tg_listen, 328204bddcbSThierry Escande .tg_configure_hw = nfcsim_tg_configure_hw, 329204bddcbSThierry Escande .tg_send_cmd = nfcsim_tg_send_cmd, 3307cbe0ff3SThierry Escande 331204bddcbSThierry Escande .abort_cmd = nfcsim_abort_cmd, 332204bddcbSThierry Escande .switch_rf = nfcsim_switch_rf, 3337cbe0ff3SThierry Escande }; 3347cbe0ff3SThierry Escande 335f9ac6273SThierry Escande static struct dentry *nfcsim_debugfs_root; 336f9ac6273SThierry Escande 337f9ac6273SThierry Escande static void nfcsim_debugfs_init(void) 338f9ac6273SThierry Escande { 339f9ac6273SThierry Escande nfcsim_debugfs_root = debugfs_create_dir("nfcsim", NULL); 340f9ac6273SThierry Escande 341f9ac6273SThierry Escande if (!nfcsim_debugfs_root) 342f9ac6273SThierry Escande pr_err("Could not create debugfs entry\n"); 343f9ac6273SThierry Escande 344f9ac6273SThierry Escande } 345f9ac6273SThierry Escande 346f9ac6273SThierry Escande static void nfcsim_debugfs_remove(void) 347f9ac6273SThierry Escande { 348f9ac6273SThierry Escande debugfs_remove_recursive(nfcsim_debugfs_root); 349f9ac6273SThierry Escande } 350f9ac6273SThierry Escande 351f9ac6273SThierry Escande static void nfcsim_debugfs_init_dev(struct nfcsim *dev) 352f9ac6273SThierry Escande { 353f9ac6273SThierry Escande struct dentry *dev_dir; 354f9ac6273SThierry Escande char devname[5]; /* nfcX\0 */ 355f9ac6273SThierry Escande u32 idx; 356f9ac6273SThierry Escande int n; 357f9ac6273SThierry Escande 358f9ac6273SThierry Escande if (!nfcsim_debugfs_root) { 359f9ac6273SThierry Escande NFCSIM_ERR(dev, "nfcsim debugfs not initialized\n"); 360f9ac6273SThierry Escande return; 361f9ac6273SThierry Escande } 362f9ac6273SThierry Escande 363f9ac6273SThierry Escande idx = dev->nfc_digital_dev->nfc_dev->idx; 364f9ac6273SThierry Escande n = snprintf(devname, sizeof(devname), "nfc%d", idx); 365f9ac6273SThierry Escande if (n >= sizeof(devname)) { 366f9ac6273SThierry Escande NFCSIM_ERR(dev, "Could not compute dev name for dev %d\n", idx); 367f9ac6273SThierry Escande return; 368f9ac6273SThierry Escande } 369f9ac6273SThierry Escande 370f9ac6273SThierry Escande dev_dir = debugfs_create_dir(devname, nfcsim_debugfs_root); 371f9ac6273SThierry Escande if (!dev_dir) { 372f9ac6273SThierry Escande NFCSIM_ERR(dev, "Could not create debugfs entries for nfc%d\n", 373f9ac6273SThierry Escande idx); 374f9ac6273SThierry Escande return; 375f9ac6273SThierry Escande } 3762a0fe4feSThierry Escande 3772a0fe4feSThierry Escande debugfs_create_u8("dropframe", 0664, dev_dir, &dev->dropframe); 378f9ac6273SThierry Escande } 379f9ac6273SThierry Escande 380204bddcbSThierry Escande static struct nfcsim *nfcsim_device_new(struct nfcsim_link *link_in, 381204bddcbSThierry Escande struct nfcsim_link *link_out) 3827cbe0ff3SThierry Escande { 3837cbe0ff3SThierry Escande struct nfcsim *dev; 384204bddcbSThierry Escande int rc; 3857cbe0ff3SThierry Escande 386204bddcbSThierry Escande dev = kzalloc(sizeof(struct nfcsim), GFP_KERNEL); 387204bddcbSThierry Escande if (!dev) 3887cbe0ff3SThierry Escande return ERR_PTR(-ENOMEM); 3897cbe0ff3SThierry Escande 390204bddcbSThierry Escande INIT_DELAYED_WORK(&dev->send_work, nfcsim_send_wq); 391204bddcbSThierry Escande INIT_WORK(&dev->recv_work, nfcsim_recv_wq); 3927cbe0ff3SThierry Escande 393204bddcbSThierry Escande dev->nfc_digital_dev = 394204bddcbSThierry Escande nfc_digital_allocate_device(&nfcsim_digital_ops, 3957cbe0ff3SThierry Escande NFC_PROTO_NFC_DEP_MASK, 396204bddcbSThierry Escande NFCSIM_CAPABILITIES, 3977cbe0ff3SThierry Escande 0, 0); 398204bddcbSThierry Escande if (!dev->nfc_digital_dev) { 399204bddcbSThierry Escande kfree(dev); 400204bddcbSThierry Escande return ERR_PTR(-ENOMEM); 401204bddcbSThierry Escande } 4027cbe0ff3SThierry Escande 403204bddcbSThierry Escande nfc_digital_set_drvdata(dev->nfc_digital_dev, dev); 4047cbe0ff3SThierry Escande 405204bddcbSThierry Escande dev->link_in = link_in; 406204bddcbSThierry Escande dev->link_out = link_out; 4077cbe0ff3SThierry Escande 408204bddcbSThierry Escande rc = nfc_digital_register_device(dev->nfc_digital_dev); 409204bddcbSThierry Escande if (rc) { 410204bddcbSThierry Escande pr_err("Could not register digital device (%d)\n", rc); 411204bddcbSThierry Escande nfc_digital_free_device(dev->nfc_digital_dev); 4127cbe0ff3SThierry Escande kfree(dev); 4137cbe0ff3SThierry Escande 4147cbe0ff3SThierry Escande return ERR_PTR(rc); 4157cbe0ff3SThierry Escande } 4167cbe0ff3SThierry Escande 417f9ac6273SThierry Escande nfcsim_debugfs_init_dev(dev); 418f9ac6273SThierry Escande 419204bddcbSThierry Escande return dev; 420204bddcbSThierry Escande } 4217cbe0ff3SThierry Escande 422204bddcbSThierry Escande static void nfcsim_device_free(struct nfcsim *dev) 423204bddcbSThierry Escande { 424204bddcbSThierry Escande nfc_digital_unregister_device(dev->nfc_digital_dev); 425204bddcbSThierry Escande 426204bddcbSThierry Escande dev->up = false; 427204bddcbSThierry Escande 428204bddcbSThierry Escande nfcsim_link_shutdown(dev->link_in); 429204bddcbSThierry Escande 430204bddcbSThierry Escande cancel_delayed_work_sync(&dev->send_work); 431204bddcbSThierry Escande cancel_work_sync(&dev->recv_work); 432204bddcbSThierry Escande 433204bddcbSThierry Escande nfc_digital_free_device(dev->nfc_digital_dev); 4347cbe0ff3SThierry Escande 4357cbe0ff3SThierry Escande kfree(dev); 4367cbe0ff3SThierry Escande } 4377cbe0ff3SThierry Escande 438204bddcbSThierry Escande static struct nfcsim *dev0; 439204bddcbSThierry Escande static struct nfcsim *dev1; 440204bddcbSThierry Escande 44140dac370SThierry Escande static int __init nfcsim_init(void) 4427cbe0ff3SThierry Escande { 443204bddcbSThierry Escande struct nfcsim_link *link0, *link1; 4447cbe0ff3SThierry Escande int rc; 4457cbe0ff3SThierry Escande 446204bddcbSThierry Escande link0 = nfcsim_link_new(); 447204bddcbSThierry Escande link1 = nfcsim_link_new(); 448204bddcbSThierry Escande if (!link0 || !link1) { 4497cbe0ff3SThierry Escande rc = -ENOMEM; 450204bddcbSThierry Escande goto exit_err; 4517cbe0ff3SThierry Escande } 4527cbe0ff3SThierry Escande 453f9ac6273SThierry Escande nfcsim_debugfs_init(); 454f9ac6273SThierry Escande 455204bddcbSThierry Escande dev0 = nfcsim_device_new(link0, link1); 4567cbe0ff3SThierry Escande if (IS_ERR(dev0)) { 4577cbe0ff3SThierry Escande rc = PTR_ERR(dev0); 458204bddcbSThierry Escande goto exit_err; 4597cbe0ff3SThierry Escande } 4607cbe0ff3SThierry Escande 461204bddcbSThierry Escande dev1 = nfcsim_device_new(link1, link0); 4627cbe0ff3SThierry Escande if (IS_ERR(dev1)) { 463204bddcbSThierry Escande nfcsim_device_free(dev0); 4647cbe0ff3SThierry Escande 4657cbe0ff3SThierry Escande rc = PTR_ERR(dev1); 466204bddcbSThierry Escande goto exit_err; 4677cbe0ff3SThierry Escande } 4687cbe0ff3SThierry Escande 469204bddcbSThierry Escande pr_info("nfcsim " NFCSIM_VERSION " initialized\n"); 4707cbe0ff3SThierry Escande 471204bddcbSThierry Escande return 0; 4727cbe0ff3SThierry Escande 473204bddcbSThierry Escande exit_err: 474204bddcbSThierry Escande pr_err("Failed to initialize nfcsim driver (%d)\n", rc); 475204bddcbSThierry Escande 4766f874bafSGustavo A. R. Silva if (link0) 477204bddcbSThierry Escande nfcsim_link_free(link0); 4786f874bafSGustavo A. R. Silva if (link1) 479204bddcbSThierry Escande nfcsim_link_free(link1); 4807cbe0ff3SThierry Escande 4817cbe0ff3SThierry Escande return rc; 4827cbe0ff3SThierry Escande } 4837cbe0ff3SThierry Escande 48440dac370SThierry Escande static void __exit nfcsim_exit(void) 4857cbe0ff3SThierry Escande { 486204bddcbSThierry Escande struct nfcsim_link *link0, *link1; 4877cbe0ff3SThierry Escande 488204bddcbSThierry Escande link0 = dev0->link_in; 489204bddcbSThierry Escande link1 = dev0->link_out; 4907cbe0ff3SThierry Escande 491204bddcbSThierry Escande nfcsim_device_free(dev0); 492204bddcbSThierry Escande nfcsim_device_free(dev1); 493204bddcbSThierry Escande 494204bddcbSThierry Escande nfcsim_link_free(link0); 495204bddcbSThierry Escande nfcsim_link_free(link1); 496f9ac6273SThierry Escande 497f9ac6273SThierry Escande nfcsim_debugfs_remove(); 4987cbe0ff3SThierry Escande } 4997cbe0ff3SThierry Escande 5007cbe0ff3SThierry Escande module_init(nfcsim_init); 5017cbe0ff3SThierry Escande module_exit(nfcsim_exit); 5027cbe0ff3SThierry Escande 5037cbe0ff3SThierry Escande MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION); 5047cbe0ff3SThierry Escande MODULE_VERSION(NFCSIM_VERSION); 5057cbe0ff3SThierry Escande MODULE_LICENSE("GPL"); 506