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> 19f9ac6273SThierry Escande #include <linux/ctype.h> 20f9ac6273SThierry Escande #include <linux/debugfs.h> 217cbe0ff3SThierry Escande #include <linux/nfc.h> 227cbe0ff3SThierry Escande #include <net/nfc/nfc.h> 23204bddcbSThierry Escande #include <net/nfc/digital.h> 247cbe0ff3SThierry Escande 25204bddcbSThierry Escande #define NFCSIM_ERR(d, fmt, args...) nfc_err(&d->nfc_digital_dev->nfc_dev->dev, \ 267cbe0ff3SThierry Escande "%s: " fmt, __func__, ## args) 277cbe0ff3SThierry Escande 28204bddcbSThierry Escande #define NFCSIM_DBG(d, fmt, args...) dev_dbg(&d->nfc_digital_dev->nfc_dev->dev, \ 297cbe0ff3SThierry Escande "%s: " fmt, __func__, ## args) 307cbe0ff3SThierry Escande 31204bddcbSThierry Escande #define NFCSIM_VERSION "0.2" 327cbe0ff3SThierry Escande 33204bddcbSThierry Escande #define NFCSIM_MODE_NONE 0 34204bddcbSThierry Escande #define NFCSIM_MODE_INITIATOR 1 35204bddcbSThierry Escande #define NFCSIM_MODE_TARGET 2 367cbe0ff3SThierry Escande 37204bddcbSThierry Escande #define NFCSIM_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC | \ 38204bddcbSThierry Escande NFC_DIGITAL_DRV_CAPS_TG_CRC) 39a440f1aaSSaurabh Sengar 407cbe0ff3SThierry Escande struct nfcsim { 41204bddcbSThierry Escande struct nfc_digital_dev *nfc_digital_dev; 427cbe0ff3SThierry Escande 43204bddcbSThierry Escande struct work_struct recv_work; 44204bddcbSThierry Escande struct delayed_work send_work; 457cbe0ff3SThierry Escande 46204bddcbSThierry Escande struct nfcsim_link *link_in; 47204bddcbSThierry Escande struct nfcsim_link *link_out; 487cbe0ff3SThierry Escande 49204bddcbSThierry Escande bool up; 50204bddcbSThierry Escande u8 mode; 51204bddcbSThierry Escande u8 rf_tech; 527cbe0ff3SThierry Escande 53204bddcbSThierry Escande u16 recv_timeout; 547cbe0ff3SThierry Escande 55204bddcbSThierry Escande nfc_digital_cmd_complete_t cb; 56204bddcbSThierry Escande void *arg; 572a0fe4feSThierry Escande 582a0fe4feSThierry Escande u8 dropframe; 597cbe0ff3SThierry Escande }; 607cbe0ff3SThierry Escande 61204bddcbSThierry Escande struct nfcsim_link { 62204bddcbSThierry Escande struct mutex lock; 637cbe0ff3SThierry Escande 64204bddcbSThierry Escande u8 rf_tech; 65204bddcbSThierry Escande u8 mode; 667cbe0ff3SThierry Escande 67204bddcbSThierry Escande u8 shutdown; 68204bddcbSThierry Escande 69204bddcbSThierry Escande struct sk_buff *skb; 70204bddcbSThierry Escande wait_queue_head_t recv_wait; 71204bddcbSThierry Escande u8 cond; 72204bddcbSThierry Escande }; 73204bddcbSThierry Escande 74204bddcbSThierry Escande static struct nfcsim_link *nfcsim_link_new(void) 757cbe0ff3SThierry Escande { 76204bddcbSThierry Escande struct nfcsim_link *link; 777cbe0ff3SThierry Escande 78204bddcbSThierry Escande link = kzalloc(sizeof(struct nfcsim_link), GFP_KERNEL); 79204bddcbSThierry Escande if (!link) 80204bddcbSThierry Escande return NULL; 817cbe0ff3SThierry Escande 82204bddcbSThierry Escande mutex_init(&link->lock); 83204bddcbSThierry Escande init_waitqueue_head(&link->recv_wait); 847cbe0ff3SThierry Escande 85204bddcbSThierry Escande return link; 867cbe0ff3SThierry Escande } 877cbe0ff3SThierry Escande 88204bddcbSThierry Escande static void nfcsim_link_free(struct nfcsim_link *link) 897cbe0ff3SThierry Escande { 90204bddcbSThierry Escande dev_kfree_skb(link->skb); 91204bddcbSThierry Escande kfree(link); 927cbe0ff3SThierry Escande } 937cbe0ff3SThierry Escande 94204bddcbSThierry Escande static void nfcsim_link_recv_wake(struct nfcsim_link *link) 957cbe0ff3SThierry Escande { 96204bddcbSThierry Escande link->cond = 1; 97204bddcbSThierry Escande wake_up_interruptible(&link->recv_wait); 987cbe0ff3SThierry Escande } 997cbe0ff3SThierry Escande 100204bddcbSThierry Escande static void nfcsim_link_set_skb(struct nfcsim_link *link, struct sk_buff *skb, 101204bddcbSThierry Escande u8 rf_tech, u8 mode) 1027cbe0ff3SThierry Escande { 103204bddcbSThierry Escande mutex_lock(&link->lock); 1047cbe0ff3SThierry Escande 105204bddcbSThierry Escande dev_kfree_skb(link->skb); 106204bddcbSThierry Escande link->skb = skb; 107204bddcbSThierry Escande link->rf_tech = rf_tech; 108204bddcbSThierry Escande link->mode = mode; 1097cbe0ff3SThierry Escande 110204bddcbSThierry Escande mutex_unlock(&link->lock); 1117cbe0ff3SThierry Escande } 1127cbe0ff3SThierry Escande 113204bddcbSThierry Escande static void nfcsim_link_recv_cancel(struct nfcsim_link *link) 114204bddcbSThierry Escande { 115204bddcbSThierry Escande mutex_lock(&link->lock); 116204bddcbSThierry Escande 117204bddcbSThierry Escande link->mode = NFCSIM_MODE_NONE; 118204bddcbSThierry Escande 119204bddcbSThierry Escande mutex_unlock(&link->lock); 120204bddcbSThierry Escande 121204bddcbSThierry Escande nfcsim_link_recv_wake(link); 122204bddcbSThierry Escande } 123204bddcbSThierry Escande 124204bddcbSThierry Escande static void nfcsim_link_shutdown(struct nfcsim_link *link) 125204bddcbSThierry Escande { 126204bddcbSThierry Escande mutex_lock(&link->lock); 127204bddcbSThierry Escande 128204bddcbSThierry Escande link->shutdown = 1; 129204bddcbSThierry Escande link->mode = NFCSIM_MODE_NONE; 130204bddcbSThierry Escande 131204bddcbSThierry Escande mutex_unlock(&link->lock); 132204bddcbSThierry Escande 133204bddcbSThierry Escande nfcsim_link_recv_wake(link); 134204bddcbSThierry Escande } 135204bddcbSThierry Escande 136204bddcbSThierry Escande static struct sk_buff *nfcsim_link_recv_skb(struct nfcsim_link *link, 137204bddcbSThierry Escande int timeout, u8 rf_tech, u8 mode) 1387cbe0ff3SThierry Escande { 1397cbe0ff3SThierry Escande int rc; 140204bddcbSThierry Escande struct sk_buff *skb; 1417cbe0ff3SThierry Escande 142204bddcbSThierry Escande rc = wait_event_interruptible_timeout(link->recv_wait, 143204bddcbSThierry Escande link->cond, 144204bddcbSThierry Escande msecs_to_jiffies(timeout)); 1457cbe0ff3SThierry Escande 146204bddcbSThierry Escande mutex_lock(&link->lock); 1477cbe0ff3SThierry Escande 148204bddcbSThierry Escande skb = link->skb; 149204bddcbSThierry Escande link->skb = NULL; 1507cbe0ff3SThierry Escande 151204bddcbSThierry Escande if (!rc) { 152204bddcbSThierry Escande rc = -ETIMEDOUT; 153204bddcbSThierry Escande goto done; 154204bddcbSThierry Escande } 1557cbe0ff3SThierry Escande 156204bddcbSThierry Escande if (!skb || link->rf_tech != rf_tech || link->mode == mode) { 157204bddcbSThierry Escande rc = -EINVAL; 158204bddcbSThierry Escande goto done; 159204bddcbSThierry Escande } 160204bddcbSThierry Escande 161204bddcbSThierry Escande if (link->shutdown) { 162204bddcbSThierry Escande rc = -ENODEV; 163204bddcbSThierry Escande goto done; 164204bddcbSThierry Escande } 165204bddcbSThierry Escande 166204bddcbSThierry Escande done: 167204bddcbSThierry Escande mutex_unlock(&link->lock); 168204bddcbSThierry Escande 169204bddcbSThierry Escande if (rc < 0) { 170204bddcbSThierry Escande dev_kfree_skb(skb); 171204bddcbSThierry Escande skb = ERR_PTR(rc); 172204bddcbSThierry Escande } 173204bddcbSThierry Escande 174204bddcbSThierry Escande link->cond = 0; 175204bddcbSThierry Escande 176204bddcbSThierry Escande return skb; 177204bddcbSThierry Escande } 178204bddcbSThierry Escande 179204bddcbSThierry Escande static void nfcsim_send_wq(struct work_struct *work) 180204bddcbSThierry Escande { 181204bddcbSThierry Escande struct nfcsim *dev = container_of(work, struct nfcsim, send_work.work); 182204bddcbSThierry Escande 183204bddcbSThierry Escande /* 184204bddcbSThierry Escande * To effectively send data, the device just wake up its link_out which 185204bddcbSThierry Escande * is the link_in of the peer device. The exchanged skb has already been 186204bddcbSThierry Escande * stored in the dev->link_out through nfcsim_link_set_skb(). 187204bddcbSThierry Escande */ 188204bddcbSThierry Escande nfcsim_link_recv_wake(dev->link_out); 189204bddcbSThierry Escande } 190204bddcbSThierry Escande 191204bddcbSThierry Escande static void nfcsim_recv_wq(struct work_struct *work) 192204bddcbSThierry Escande { 193204bddcbSThierry Escande struct nfcsim *dev = container_of(work, struct nfcsim, recv_work); 194204bddcbSThierry Escande struct sk_buff *skb; 195204bddcbSThierry Escande 196204bddcbSThierry Escande skb = nfcsim_link_recv_skb(dev->link_in, dev->recv_timeout, 197204bddcbSThierry Escande dev->rf_tech, dev->mode); 198204bddcbSThierry Escande 199204bddcbSThierry Escande if (!dev->up) { 200204bddcbSThierry Escande NFCSIM_ERR(dev, "Device is down\n"); 201204bddcbSThierry Escande 202204bddcbSThierry Escande if (!IS_ERR(skb)) 203204bddcbSThierry Escande dev_kfree_skb(skb); 204204bddcbSThierry Escande 205204bddcbSThierry Escande skb = ERR_PTR(-ENODEV); 206204bddcbSThierry Escande } 207204bddcbSThierry Escande 208204bddcbSThierry Escande dev->cb(dev->nfc_digital_dev, dev->arg, skb); 209204bddcbSThierry Escande } 210204bddcbSThierry Escande 211204bddcbSThierry Escande static int nfcsim_send(struct nfc_digital_dev *ddev, struct sk_buff *skb, 212204bddcbSThierry Escande u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) 213204bddcbSThierry Escande { 214204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 215204bddcbSThierry Escande u8 delay; 216204bddcbSThierry Escande 217204bddcbSThierry Escande if (!dev->up) { 218204bddcbSThierry Escande NFCSIM_ERR(dev, "Device is down\n"); 219204bddcbSThierry Escande return -ENODEV; 220204bddcbSThierry Escande } 221204bddcbSThierry Escande 222204bddcbSThierry Escande dev->recv_timeout = timeout; 223204bddcbSThierry Escande dev->cb = cb; 224204bddcbSThierry Escande dev->arg = arg; 225204bddcbSThierry Escande 226204bddcbSThierry Escande schedule_work(&dev->recv_work); 227204bddcbSThierry Escande 2282a0fe4feSThierry Escande if (dev->dropframe) { 2292a0fe4feSThierry Escande NFCSIM_DBG(dev, "dropping frame (out of %d)\n", dev->dropframe); 2302a0fe4feSThierry Escande dev_kfree_skb(skb); 2312a0fe4feSThierry Escande dev->dropframe--; 2322a0fe4feSThierry Escande 2332a0fe4feSThierry Escande return 0; 2342a0fe4feSThierry Escande } 2352a0fe4feSThierry Escande 236204bddcbSThierry Escande if (skb) { 237204bddcbSThierry Escande nfcsim_link_set_skb(dev->link_out, skb, dev->rf_tech, 238204bddcbSThierry Escande dev->mode); 239204bddcbSThierry Escande 240204bddcbSThierry Escande /* Add random delay (between 3 and 10 ms) before sending data */ 241204bddcbSThierry Escande get_random_bytes(&delay, 1); 242204bddcbSThierry Escande delay = 3 + (delay & 0x07); 243204bddcbSThierry Escande 244204bddcbSThierry Escande schedule_delayed_work(&dev->send_work, msecs_to_jiffies(delay)); 245204bddcbSThierry Escande } 246204bddcbSThierry Escande 247204bddcbSThierry Escande return 0; 248204bddcbSThierry Escande } 249204bddcbSThierry Escande 250204bddcbSThierry Escande static void nfcsim_abort_cmd(struct nfc_digital_dev *ddev) 251204bddcbSThierry Escande { 252204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 253204bddcbSThierry Escande 254204bddcbSThierry Escande nfcsim_link_recv_cancel(dev->link_in); 255204bddcbSThierry Escande } 256204bddcbSThierry Escande 257204bddcbSThierry Escande static int nfcsim_switch_rf(struct nfc_digital_dev *ddev, bool on) 258204bddcbSThierry Escande { 259204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 260204bddcbSThierry Escande 261204bddcbSThierry Escande dev->up = on; 262204bddcbSThierry Escande 263204bddcbSThierry Escande return 0; 264204bddcbSThierry Escande } 265204bddcbSThierry Escande 266204bddcbSThierry Escande static int nfcsim_in_configure_hw(struct nfc_digital_dev *ddev, 267204bddcbSThierry Escande int type, int param) 268204bddcbSThierry Escande { 269204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 270204bddcbSThierry Escande 271204bddcbSThierry Escande switch (type) { 272204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_RF_TECH: 273204bddcbSThierry Escande dev->up = true; 274204bddcbSThierry Escande dev->mode = NFCSIM_MODE_INITIATOR; 275204bddcbSThierry Escande dev->rf_tech = param; 276204bddcbSThierry Escande break; 277204bddcbSThierry Escande 278204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_FRAMING: 279204bddcbSThierry Escande break; 280204bddcbSThierry Escande 281204bddcbSThierry Escande default: 282204bddcbSThierry Escande NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type); 2837cbe0ff3SThierry Escande return -EINVAL; 2847cbe0ff3SThierry Escande } 2857cbe0ff3SThierry Escande 286204bddcbSThierry Escande return 0; 2877cbe0ff3SThierry Escande } 2887cbe0ff3SThierry Escande 289204bddcbSThierry Escande static int nfcsim_in_send_cmd(struct nfc_digital_dev *ddev, 290204bddcbSThierry Escande struct sk_buff *skb, u16 timeout, 291204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 2927cbe0ff3SThierry Escande { 293204bddcbSThierry Escande return nfcsim_send(ddev, skb, timeout, cb, arg); 294204bddcbSThierry Escande } 2957cbe0ff3SThierry Escande 296204bddcbSThierry Escande static int nfcsim_tg_configure_hw(struct nfc_digital_dev *ddev, 297204bddcbSThierry Escande int type, int param) 298204bddcbSThierry Escande { 299204bddcbSThierry Escande struct nfcsim *dev = nfc_digital_get_drvdata(ddev); 3007cbe0ff3SThierry Escande 301204bddcbSThierry Escande switch (type) { 302204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_RF_TECH: 303204bddcbSThierry Escande dev->up = true; 304204bddcbSThierry Escande dev->mode = NFCSIM_MODE_TARGET; 305204bddcbSThierry Escande dev->rf_tech = param; 306204bddcbSThierry Escande break; 307204bddcbSThierry Escande 308204bddcbSThierry Escande case NFC_DIGITAL_CONFIG_FRAMING: 309204bddcbSThierry Escande break; 310204bddcbSThierry Escande 311204bddcbSThierry Escande default: 312204bddcbSThierry Escande NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type); 313204bddcbSThierry Escande return -EINVAL; 314204bddcbSThierry Escande } 3157cbe0ff3SThierry Escande 3167cbe0ff3SThierry Escande return 0; 3177cbe0ff3SThierry Escande } 3187cbe0ff3SThierry Escande 319204bddcbSThierry Escande static int nfcsim_tg_send_cmd(struct nfc_digital_dev *ddev, 320204bddcbSThierry Escande struct sk_buff *skb, u16 timeout, 321204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 3227cbe0ff3SThierry Escande { 323204bddcbSThierry Escande return nfcsim_send(ddev, skb, timeout, cb, arg); 3247cbe0ff3SThierry Escande } 3257cbe0ff3SThierry Escande 326204bddcbSThierry Escande static int nfcsim_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, 327204bddcbSThierry Escande nfc_digital_cmd_complete_t cb, void *arg) 3287cbe0ff3SThierry Escande { 329204bddcbSThierry Escande return nfcsim_send(ddev, NULL, timeout, cb, arg); 3307cbe0ff3SThierry Escande } 3317cbe0ff3SThierry Escande 332204bddcbSThierry Escande static struct nfc_digital_ops nfcsim_digital_ops = { 333204bddcbSThierry Escande .in_configure_hw = nfcsim_in_configure_hw, 334204bddcbSThierry Escande .in_send_cmd = nfcsim_in_send_cmd, 3357cbe0ff3SThierry Escande 336204bddcbSThierry Escande .tg_listen = nfcsim_tg_listen, 337204bddcbSThierry Escande .tg_configure_hw = nfcsim_tg_configure_hw, 338204bddcbSThierry Escande .tg_send_cmd = nfcsim_tg_send_cmd, 3397cbe0ff3SThierry Escande 340204bddcbSThierry Escande .abort_cmd = nfcsim_abort_cmd, 341204bddcbSThierry Escande .switch_rf = nfcsim_switch_rf, 3427cbe0ff3SThierry Escande }; 3437cbe0ff3SThierry Escande 344f9ac6273SThierry Escande static struct dentry *nfcsim_debugfs_root; 345f9ac6273SThierry Escande 346f9ac6273SThierry Escande static void nfcsim_debugfs_init(void) 347f9ac6273SThierry Escande { 348f9ac6273SThierry Escande nfcsim_debugfs_root = debugfs_create_dir("nfcsim", NULL); 349f9ac6273SThierry Escande 350f9ac6273SThierry Escande if (!nfcsim_debugfs_root) 351f9ac6273SThierry Escande pr_err("Could not create debugfs entry\n"); 352f9ac6273SThierry Escande 353f9ac6273SThierry Escande } 354f9ac6273SThierry Escande 355f9ac6273SThierry Escande static void nfcsim_debugfs_remove(void) 356f9ac6273SThierry Escande { 357f9ac6273SThierry Escande debugfs_remove_recursive(nfcsim_debugfs_root); 358f9ac6273SThierry Escande } 359f9ac6273SThierry Escande 360f9ac6273SThierry Escande static void nfcsim_debugfs_init_dev(struct nfcsim *dev) 361f9ac6273SThierry Escande { 362f9ac6273SThierry Escande struct dentry *dev_dir; 363f9ac6273SThierry Escande char devname[5]; /* nfcX\0 */ 364f9ac6273SThierry Escande u32 idx; 365f9ac6273SThierry Escande int n; 366f9ac6273SThierry Escande 367f9ac6273SThierry Escande if (!nfcsim_debugfs_root) { 368f9ac6273SThierry Escande NFCSIM_ERR(dev, "nfcsim debugfs not initialized\n"); 369f9ac6273SThierry Escande return; 370f9ac6273SThierry Escande } 371f9ac6273SThierry Escande 372f9ac6273SThierry Escande idx = dev->nfc_digital_dev->nfc_dev->idx; 373f9ac6273SThierry Escande n = snprintf(devname, sizeof(devname), "nfc%d", idx); 374f9ac6273SThierry Escande if (n >= sizeof(devname)) { 375f9ac6273SThierry Escande NFCSIM_ERR(dev, "Could not compute dev name for dev %d\n", idx); 376f9ac6273SThierry Escande return; 377f9ac6273SThierry Escande } 378f9ac6273SThierry Escande 379f9ac6273SThierry Escande dev_dir = debugfs_create_dir(devname, nfcsim_debugfs_root); 380f9ac6273SThierry Escande if (!dev_dir) { 381f9ac6273SThierry Escande NFCSIM_ERR(dev, "Could not create debugfs entries for nfc%d\n", 382f9ac6273SThierry Escande idx); 383f9ac6273SThierry Escande return; 384f9ac6273SThierry Escande } 3852a0fe4feSThierry Escande 3862a0fe4feSThierry Escande debugfs_create_u8("dropframe", 0664, dev_dir, &dev->dropframe); 387f9ac6273SThierry Escande } 388f9ac6273SThierry Escande 389204bddcbSThierry Escande static struct nfcsim *nfcsim_device_new(struct nfcsim_link *link_in, 390204bddcbSThierry Escande struct nfcsim_link *link_out) 3917cbe0ff3SThierry Escande { 3927cbe0ff3SThierry Escande struct nfcsim *dev; 393204bddcbSThierry Escande int rc; 3947cbe0ff3SThierry Escande 395204bddcbSThierry Escande dev = kzalloc(sizeof(struct nfcsim), GFP_KERNEL); 396204bddcbSThierry Escande if (!dev) 3977cbe0ff3SThierry Escande return ERR_PTR(-ENOMEM); 3987cbe0ff3SThierry Escande 399204bddcbSThierry Escande INIT_DELAYED_WORK(&dev->send_work, nfcsim_send_wq); 400204bddcbSThierry Escande INIT_WORK(&dev->recv_work, nfcsim_recv_wq); 4017cbe0ff3SThierry Escande 402204bddcbSThierry Escande dev->nfc_digital_dev = 403204bddcbSThierry Escande nfc_digital_allocate_device(&nfcsim_digital_ops, 4047cbe0ff3SThierry Escande NFC_PROTO_NFC_DEP_MASK, 405204bddcbSThierry Escande NFCSIM_CAPABILITIES, 4067cbe0ff3SThierry Escande 0, 0); 407204bddcbSThierry Escande if (!dev->nfc_digital_dev) { 408204bddcbSThierry Escande kfree(dev); 409204bddcbSThierry Escande return ERR_PTR(-ENOMEM); 410204bddcbSThierry Escande } 4117cbe0ff3SThierry Escande 412204bddcbSThierry Escande nfc_digital_set_drvdata(dev->nfc_digital_dev, dev); 4137cbe0ff3SThierry Escande 414204bddcbSThierry Escande dev->link_in = link_in; 415204bddcbSThierry Escande dev->link_out = link_out; 4167cbe0ff3SThierry Escande 417204bddcbSThierry Escande rc = nfc_digital_register_device(dev->nfc_digital_dev); 418204bddcbSThierry Escande if (rc) { 419204bddcbSThierry Escande pr_err("Could not register digital device (%d)\n", rc); 420204bddcbSThierry Escande nfc_digital_free_device(dev->nfc_digital_dev); 4217cbe0ff3SThierry Escande kfree(dev); 4227cbe0ff3SThierry Escande 4237cbe0ff3SThierry Escande return ERR_PTR(rc); 4247cbe0ff3SThierry Escande } 4257cbe0ff3SThierry Escande 426f9ac6273SThierry Escande nfcsim_debugfs_init_dev(dev); 427f9ac6273SThierry Escande 428204bddcbSThierry Escande return dev; 429204bddcbSThierry Escande } 4307cbe0ff3SThierry Escande 431204bddcbSThierry Escande static void nfcsim_device_free(struct nfcsim *dev) 432204bddcbSThierry Escande { 433204bddcbSThierry Escande nfc_digital_unregister_device(dev->nfc_digital_dev); 434204bddcbSThierry Escande 435204bddcbSThierry Escande dev->up = false; 436204bddcbSThierry Escande 437204bddcbSThierry Escande nfcsim_link_shutdown(dev->link_in); 438204bddcbSThierry Escande 439204bddcbSThierry Escande cancel_delayed_work_sync(&dev->send_work); 440204bddcbSThierry Escande cancel_work_sync(&dev->recv_work); 441204bddcbSThierry Escande 442204bddcbSThierry Escande nfc_digital_free_device(dev->nfc_digital_dev); 4437cbe0ff3SThierry Escande 4447cbe0ff3SThierry Escande kfree(dev); 4457cbe0ff3SThierry Escande } 4467cbe0ff3SThierry Escande 447204bddcbSThierry Escande static struct nfcsim *dev0; 448204bddcbSThierry Escande static struct nfcsim *dev1; 449204bddcbSThierry Escande 45040dac370SThierry Escande static int __init nfcsim_init(void) 4517cbe0ff3SThierry Escande { 452204bddcbSThierry Escande struct nfcsim_link *link0, *link1; 4537cbe0ff3SThierry Escande int rc; 4547cbe0ff3SThierry Escande 455204bddcbSThierry Escande link0 = nfcsim_link_new(); 456204bddcbSThierry Escande link1 = nfcsim_link_new(); 457204bddcbSThierry Escande if (!link0 || !link1) { 4587cbe0ff3SThierry Escande rc = -ENOMEM; 459204bddcbSThierry Escande goto exit_err; 4607cbe0ff3SThierry Escande } 4617cbe0ff3SThierry Escande 462f9ac6273SThierry Escande nfcsim_debugfs_init(); 463f9ac6273SThierry Escande 464204bddcbSThierry Escande dev0 = nfcsim_device_new(link0, link1); 4657cbe0ff3SThierry Escande if (IS_ERR(dev0)) { 4667cbe0ff3SThierry Escande rc = PTR_ERR(dev0); 467204bddcbSThierry Escande goto exit_err; 4687cbe0ff3SThierry Escande } 4697cbe0ff3SThierry Escande 470204bddcbSThierry Escande dev1 = nfcsim_device_new(link1, link0); 4717cbe0ff3SThierry Escande if (IS_ERR(dev1)) { 472204bddcbSThierry Escande nfcsim_device_free(dev0); 4737cbe0ff3SThierry Escande 4747cbe0ff3SThierry Escande rc = PTR_ERR(dev1); 475204bddcbSThierry Escande goto exit_err; 4767cbe0ff3SThierry Escande } 4777cbe0ff3SThierry Escande 478204bddcbSThierry Escande pr_info("nfcsim " NFCSIM_VERSION " initialized\n"); 4797cbe0ff3SThierry Escande 480204bddcbSThierry Escande return 0; 4817cbe0ff3SThierry Escande 482204bddcbSThierry Escande exit_err: 483204bddcbSThierry Escande pr_err("Failed to initialize nfcsim driver (%d)\n", rc); 484204bddcbSThierry Escande 485*6f874bafSGustavo A. R. Silva if (link0) 486204bddcbSThierry Escande nfcsim_link_free(link0); 487*6f874bafSGustavo A. R. Silva if (link1) 488204bddcbSThierry Escande nfcsim_link_free(link1); 4897cbe0ff3SThierry Escande 4907cbe0ff3SThierry Escande return rc; 4917cbe0ff3SThierry Escande } 4927cbe0ff3SThierry Escande 49340dac370SThierry Escande static void __exit nfcsim_exit(void) 4947cbe0ff3SThierry Escande { 495204bddcbSThierry Escande struct nfcsim_link *link0, *link1; 4967cbe0ff3SThierry Escande 497204bddcbSThierry Escande link0 = dev0->link_in; 498204bddcbSThierry Escande link1 = dev0->link_out; 4997cbe0ff3SThierry Escande 500204bddcbSThierry Escande nfcsim_device_free(dev0); 501204bddcbSThierry Escande nfcsim_device_free(dev1); 502204bddcbSThierry Escande 503204bddcbSThierry Escande nfcsim_link_free(link0); 504204bddcbSThierry Escande nfcsim_link_free(link1); 505f9ac6273SThierry Escande 506f9ac6273SThierry Escande nfcsim_debugfs_remove(); 5077cbe0ff3SThierry Escande } 5087cbe0ff3SThierry Escande 5097cbe0ff3SThierry Escande module_init(nfcsim_init); 5107cbe0ff3SThierry Escande module_exit(nfcsim_exit); 5117cbe0ff3SThierry Escande 5127cbe0ff3SThierry Escande MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION); 5137cbe0ff3SThierry Escande MODULE_VERSION(NFCSIM_VERSION); 5147cbe0ff3SThierry Escande MODULE_LICENSE("GPL"); 515