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); 195*5e7b30d2SKrzysztof Kozlowski return; 196204bddcbSThierry Escande } 197204bddcbSThierry Escande 198204bddcbSThierry Escande dev->cb(dev->nfc_digital_dev, dev->arg, skb); 199204bddcbSThierry Escande } 200204bddcbSThierry Escande 201204bddcbSThierry Escande static int nfcsim_send(struct nfc_digital_dev *ddev, struct sk_buff *skb, 202204bddcbSThierry Escande u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) 203204bddcbSThierry Escande { 204204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 205204bddcbSThierry Escande u8 delay; 206204bddcbSThierry Escande 207204bddcbSThierry Escande if (!dev->up) { 208204bddcbSThierry Escande NFCSIM_ERR(dev, "Device is down\n"); 209204bddcbSThierry Escande return -ENODEV; 210204bddcbSThierry Escande } 211204bddcbSThierry Escande 212204bddcbSThierry Escande dev->recv_timeout = timeout; 213204bddcbSThierry Escande dev->cb = cb; 214204bddcbSThierry Escande dev->arg = arg; 215204bddcbSThierry Escande 216204bddcbSThierry Escande schedule_work(&dev->recv_work); 217204bddcbSThierry Escande 2182a0fe4feSThierry Escande if (dev->dropframe) { 2192a0fe4feSThierry Escande NFCSIM_DBG(dev, "dropping frame (out of %d)\n", dev->dropframe); 2202a0fe4feSThierry Escande dev_kfree_skb(skb); 2212a0fe4feSThierry Escande dev->dropframe--; 2222a0fe4feSThierry Escande 2232a0fe4feSThierry Escande return 0; 2242a0fe4feSThierry Escande } 2252a0fe4feSThierry Escande 226204bddcbSThierry Escande if (skb) { 227204bddcbSThierry Escande nfcsim_link_set_skb(dev->link_out, skb, dev->rf_tech, 228204bddcbSThierry Escande dev->mode); 229204bddcbSThierry Escande 230204bddcbSThierry Escande /* Add random delay (between 3 and 10 ms) before sending data */ 231204bddcbSThierry Escande get_random_bytes(&delay, 1); 232204bddcbSThierry Escande delay = 3 + (delay & 0x07); 233204bddcbSThierry Escande 234204bddcbSThierry Escande schedule_delayed_work(&dev->send_work, msecs_to_jiffies(delay)); 235204bddcbSThierry Escande } 236204bddcbSThierry Escande 237204bddcbSThierry Escande return 0; 238204bddcbSThierry Escande } 239204bddcbSThierry Escande 240204bddcbSThierry Escande static void nfcsim_abort_cmd(struct nfc_digital_dev *ddev) 241204bddcbSThierry Escande { 242204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 243204bddcbSThierry Escande 244204bddcbSThierry Escande nfcsim_link_recv_cancel(dev->link_in); 245204bddcbSThierry Escande } 246204bddcbSThierry Escande 247204bddcbSThierry Escande static int nfcsim_switch_rf(struct nfc_digital_dev *ddev, bool on) 248204bddcbSThierry Escande { 249204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 250204bddcbSThierry Escande 251204bddcbSThierry Escande dev->up = on; 252204bddcbSThierry Escande 253204bddcbSThierry Escande return 0; 254204bddcbSThierry Escande } 255204bddcbSThierry Escande 256204bddcbSThierry Escande static int nfcsim_in_configure_hw(struct nfc_digital_dev *ddev, 257204bddcbSThierry Escande int type, int param) 258204bddcbSThierry Escande { 259204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 260204bddcbSThierry Escande 261204bddcbSThierry Escande switch (type) { 262204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_RF_TECH: 263204bddcbSThierry Escande dev->up = true; 264204bddcbSThierry Escande dev->mode = NFCSIM_MODE_INITIATOR; 265204bddcbSThierry Escande dev->rf_tech = param; 266204bddcbSThierry Escande break; 267204bddcbSThierry Escande 268204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_FRAMING: 269204bddcbSThierry Escande break; 270204bddcbSThierry Escande 271204bddcbSThierry Escande default: 272204bddcbSThierry Escande NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type); 2737cbe0ff3SThierry Escande return -EINVAL; 2747cbe0ff3SThierry Escande } 2757cbe0ff3SThierry Escande 276204bddcbSThierry Escande return 0; 2777cbe0ff3SThierry Escande } 2787cbe0ff3SThierry Escande 279204bddcbSThierry Escande static int nfcsim_in_send_cmd(struct nfc_digital_dev *ddev, 280204bddcbSThierry Escande struct sk_buff *skb, u16 timeout, 281204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 2827cbe0ff3SThierry Escande { 283204bddcbSThierry Escande return nfcsim_send(ddev, skb, timeout, cb, arg); 284204bddcbSThierry Escande } 2857cbe0ff3SThierry Escande 286204bddcbSThierry Escande static int nfcsim_tg_configure_hw(struct nfc_digital_dev *ddev, 287204bddcbSThierry Escande int type, int param) 288204bddcbSThierry Escande { 289204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 2907cbe0ff3SThierry Escande 291204bddcbSThierry Escande switch (type) { 292204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_RF_TECH: 293204bddcbSThierry Escande dev->up = true; 294204bddcbSThierry Escande dev->mode = NFCSIM_MODE_TARGET; 295204bddcbSThierry Escande dev->rf_tech = param; 296204bddcbSThierry Escande break; 297204bddcbSThierry Escande 298204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_FRAMING: 299204bddcbSThierry Escande break; 300204bddcbSThierry Escande 301204bddcbSThierry Escande default: 302204bddcbSThierry Escande NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type); 303204bddcbSThierry Escande return -EINVAL; 304204bddcbSThierry Escande } 3057cbe0ff3SThierry Escande 3067cbe0ff3SThierry Escande return 0; 3077cbe0ff3SThierry Escande } 3087cbe0ff3SThierry Escande 309204bddcbSThierry Escande static int nfcsim_tg_send_cmd(struct nfc_digital_dev *ddev, 310204bddcbSThierry Escande struct sk_buff *skb, u16 timeout, 311204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 3127cbe0ff3SThierry Escande { 313204bddcbSThierry Escande return nfcsim_send(ddev, skb, timeout, cb, arg); 3147cbe0ff3SThierry Escande } 3157cbe0ff3SThierry Escande 316204bddcbSThierry Escande static int nfcsim_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, 317204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 3187cbe0ff3SThierry Escande { 319204bddcbSThierry Escande return nfcsim_send(ddev, NULL, timeout, cb, arg); 3207cbe0ff3SThierry Escande } 3217cbe0ff3SThierry Escande 322204bddcbSThierry Escande static struct nfc_digital_ops nfcsim_digital_ops = { 323204bddcbSThierry Escande .in_configure_hw = nfcsim_in_configure_hw, 324204bddcbSThierry Escande .in_send_cmd = nfcsim_in_send_cmd, 3257cbe0ff3SThierry Escande 326204bddcbSThierry Escande .tg_listen = nfcsim_tg_listen, 327204bddcbSThierry Escande .tg_configure_hw = nfcsim_tg_configure_hw, 328204bddcbSThierry Escande .tg_send_cmd = nfcsim_tg_send_cmd, 3297cbe0ff3SThierry Escande 330204bddcbSThierry Escande .abort_cmd = nfcsim_abort_cmd, 331204bddcbSThierry Escande .switch_rf = nfcsim_switch_rf, 3327cbe0ff3SThierry Escande }; 3337cbe0ff3SThierry Escande 334f9ac6273SThierry Escande static struct dentry *nfcsim_debugfs_root; 335f9ac6273SThierry Escande 336f9ac6273SThierry Escande static void nfcsim_debugfs_init(void) 337f9ac6273SThierry Escande { 338f9ac6273SThierry Escande nfcsim_debugfs_root = debugfs_create_dir("nfcsim", NULL); 339f9ac6273SThierry Escande 340f9ac6273SThierry Escande if (!nfcsim_debugfs_root) 341f9ac6273SThierry Escande pr_err("Could not create debugfs entry\n"); 342f9ac6273SThierry Escande 343f9ac6273SThierry Escande } 344f9ac6273SThierry Escande 345f9ac6273SThierry Escande static void nfcsim_debugfs_remove(void) 346f9ac6273SThierry Escande { 347f9ac6273SThierry Escande debugfs_remove_recursive(nfcsim_debugfs_root); 348f9ac6273SThierry Escande } 349f9ac6273SThierry Escande 350f9ac6273SThierry Escande static void nfcsim_debugfs_init_dev(struct nfcsim *dev) 351f9ac6273SThierry Escande { 352f9ac6273SThierry Escande struct dentry *dev_dir; 353f9ac6273SThierry Escande char devname[5]; /* nfcX\0 */ 354f9ac6273SThierry Escande u32 idx; 355f9ac6273SThierry Escande int n; 356f9ac6273SThierry Escande 357f9ac6273SThierry Escande if (!nfcsim_debugfs_root) { 358f9ac6273SThierry Escande NFCSIM_ERR(dev, "nfcsim debugfs not initialized\n"); 359f9ac6273SThierry Escande return; 360f9ac6273SThierry Escande } 361f9ac6273SThierry Escande 362f9ac6273SThierry Escande idx = dev->nfc_digital_dev->nfc_dev->idx; 363f9ac6273SThierry Escande n = snprintf(devname, sizeof(devname), "nfc%d", idx); 364f9ac6273SThierry Escande if (n >= sizeof(devname)) { 365f9ac6273SThierry Escande NFCSIM_ERR(dev, "Could not compute dev name for dev %d\n", idx); 366f9ac6273SThierry Escande return; 367f9ac6273SThierry Escande } 368f9ac6273SThierry Escande 369f9ac6273SThierry Escande dev_dir = debugfs_create_dir(devname, nfcsim_debugfs_root); 370f9ac6273SThierry Escande if (!dev_dir) { 371f9ac6273SThierry Escande NFCSIM_ERR(dev, "Could not create debugfs entries for nfc%d\n", 372f9ac6273SThierry Escande idx); 373f9ac6273SThierry Escande return; 374f9ac6273SThierry Escande } 3752a0fe4feSThierry Escande 3762a0fe4feSThierry Escande debugfs_create_u8("dropframe", 0664, dev_dir, &dev->dropframe); 377f9ac6273SThierry Escande } 378f9ac6273SThierry Escande 379204bddcbSThierry Escande static struct nfcsim *nfcsim_device_new(struct nfcsim_link *link_in, 380204bddcbSThierry Escande struct nfcsim_link *link_out) 3817cbe0ff3SThierry Escande { 3827cbe0ff3SThierry Escande struct nfcsim *dev; 383204bddcbSThierry Escande int rc; 3847cbe0ff3SThierry Escande 385204bddcbSThierry Escande dev = kzalloc(sizeof(struct nfcsim), GFP_KERNEL); 386204bddcbSThierry Escande if (!dev) 3877cbe0ff3SThierry Escande return ERR_PTR(-ENOMEM); 3887cbe0ff3SThierry Escande 389204bddcbSThierry Escande INIT_DELAYED_WORK(&dev->send_work, nfcsim_send_wq); 390204bddcbSThierry Escande INIT_WORK(&dev->recv_work, nfcsim_recv_wq); 3917cbe0ff3SThierry Escande 392204bddcbSThierry Escande dev->nfc_digital_dev = 393204bddcbSThierry Escande nfc_digital_allocate_device(&nfcsim_digital_ops, 3947cbe0ff3SThierry Escande NFC_PROTO_NFC_DEP_MASK, 395204bddcbSThierry Escande NFCSIM_CAPABILITIES, 3967cbe0ff3SThierry Escande 0, 0); 397204bddcbSThierry Escande if (!dev->nfc_digital_dev) { 398204bddcbSThierry Escande kfree(dev); 399204bddcbSThierry Escande return ERR_PTR(-ENOMEM); 400204bddcbSThierry Escande } 4017cbe0ff3SThierry Escande 402204bddcbSThierry Escande nfc_digital_set_drvdata(dev->nfc_digital_dev, dev); 4037cbe0ff3SThierry Escande 404204bddcbSThierry Escande dev->link_in = link_in; 405204bddcbSThierry Escande dev->link_out = link_out; 4067cbe0ff3SThierry Escande 407204bddcbSThierry Escande rc = nfc_digital_register_device(dev->nfc_digital_dev); 408204bddcbSThierry Escande if (rc) { 409204bddcbSThierry Escande pr_err("Could not register digital device (%d)\n", rc); 410204bddcbSThierry Escande nfc_digital_free_device(dev->nfc_digital_dev); 4117cbe0ff3SThierry Escande kfree(dev); 4127cbe0ff3SThierry Escande 4137cbe0ff3SThierry Escande return ERR_PTR(rc); 4147cbe0ff3SThierry Escande } 4157cbe0ff3SThierry Escande 416f9ac6273SThierry Escande nfcsim_debugfs_init_dev(dev); 417f9ac6273SThierry Escande 418204bddcbSThierry Escande return dev; 419204bddcbSThierry Escande } 4207cbe0ff3SThierry Escande 421204bddcbSThierry Escande static void nfcsim_device_free(struct nfcsim *dev) 422204bddcbSThierry Escande { 423204bddcbSThierry Escande nfc_digital_unregister_device(dev->nfc_digital_dev); 424204bddcbSThierry Escande 425204bddcbSThierry Escande dev->up = false; 426204bddcbSThierry Escande 427204bddcbSThierry Escande nfcsim_link_shutdown(dev->link_in); 428204bddcbSThierry Escande 429204bddcbSThierry Escande cancel_delayed_work_sync(&dev->send_work); 430204bddcbSThierry Escande cancel_work_sync(&dev->recv_work); 431204bddcbSThierry Escande 432204bddcbSThierry Escande nfc_digital_free_device(dev->nfc_digital_dev); 4337cbe0ff3SThierry Escande 4347cbe0ff3SThierry Escande kfree(dev); 4357cbe0ff3SThierry Escande } 4367cbe0ff3SThierry Escande 437204bddcbSThierry Escande static struct nfcsim *dev0; 438204bddcbSThierry Escande static struct nfcsim *dev1; 439204bddcbSThierry Escande 44040dac370SThierry Escande static int __init nfcsim_init(void) 4417cbe0ff3SThierry Escande { 442204bddcbSThierry Escande struct nfcsim_link *link0, *link1; 4437cbe0ff3SThierry Escande int rc; 4447cbe0ff3SThierry Escande 445204bddcbSThierry Escande link0 = nfcsim_link_new(); 446204bddcbSThierry Escande link1 = nfcsim_link_new(); 447204bddcbSThierry Escande if (!link0 || !link1) { 4487cbe0ff3SThierry Escande rc = -ENOMEM; 449204bddcbSThierry Escande goto exit_err; 4507cbe0ff3SThierry Escande } 4517cbe0ff3SThierry Escande 452f9ac6273SThierry Escande nfcsim_debugfs_init(); 453f9ac6273SThierry Escande 454204bddcbSThierry Escande dev0 = nfcsim_device_new(link0, link1); 4557cbe0ff3SThierry Escande if (IS_ERR(dev0)) { 4567cbe0ff3SThierry Escande rc = PTR_ERR(dev0); 457204bddcbSThierry Escande goto exit_err; 4587cbe0ff3SThierry Escande } 4597cbe0ff3SThierry Escande 460204bddcbSThierry Escande dev1 = nfcsim_device_new(link1, link0); 4617cbe0ff3SThierry Escande if (IS_ERR(dev1)) { 462204bddcbSThierry Escande nfcsim_device_free(dev0); 4637cbe0ff3SThierry Escande 4647cbe0ff3SThierry Escande rc = PTR_ERR(dev1); 465204bddcbSThierry Escande goto exit_err; 4667cbe0ff3SThierry Escande } 4677cbe0ff3SThierry Escande 468204bddcbSThierry Escande pr_info("nfcsim " NFCSIM_VERSION " initialized\n"); 4697cbe0ff3SThierry Escande 470204bddcbSThierry Escande return 0; 4717cbe0ff3SThierry Escande 472204bddcbSThierry Escande exit_err: 473204bddcbSThierry Escande pr_err("Failed to initialize nfcsim driver (%d)\n", rc); 474204bddcbSThierry Escande 4756f874bafSGustavo A. R. Silva if (link0) 476204bddcbSThierry Escande nfcsim_link_free(link0); 4776f874bafSGustavo A. R. Silva if (link1) 478204bddcbSThierry Escande nfcsim_link_free(link1); 4797cbe0ff3SThierry Escande 4807cbe0ff3SThierry Escande return rc; 4817cbe0ff3SThierry Escande } 4827cbe0ff3SThierry Escande 48340dac370SThierry Escande static void __exit nfcsim_exit(void) 4847cbe0ff3SThierry Escande { 485204bddcbSThierry Escande struct nfcsim_link *link0, *link1; 4867cbe0ff3SThierry Escande 487204bddcbSThierry Escande link0 = dev0->link_in; 488204bddcbSThierry Escande link1 = dev0->link_out; 4897cbe0ff3SThierry Escande 490204bddcbSThierry Escande nfcsim_device_free(dev0); 491204bddcbSThierry Escande nfcsim_device_free(dev1); 492204bddcbSThierry Escande 493204bddcbSThierry Escande nfcsim_link_free(link0); 494204bddcbSThierry Escande nfcsim_link_free(link1); 495f9ac6273SThierry Escande 496f9ac6273SThierry Escande nfcsim_debugfs_remove(); 4977cbe0ff3SThierry Escande } 4987cbe0ff3SThierry Escande 4997cbe0ff3SThierry Escande module_init(nfcsim_init); 5007cbe0ff3SThierry Escande module_exit(nfcsim_exit); 5017cbe0ff3SThierry Escande 5027cbe0ff3SThierry Escande MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION); 5037cbe0ff3SThierry Escande MODULE_VERSION(NFCSIM_VERSION); 5047cbe0ff3SThierry Escande MODULE_LICENSE("GPL"); 505