linux/drivers/nfc/nfcsim.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * NFC hardware simulation driver
   4 * Copyright (c) 2013, Intel Corporation.
   5 */
   6
   7#include <linux/device.h>
   8#include <linux/kernel.h>
   9#include <linux/module.h>
  10#include <linux/ctype.h>
  11#include <linux/debugfs.h>
  12#include <linux/nfc.h>
  13#include <net/nfc/nfc.h>
  14#include <net/nfc/digital.h>
  15
  16#define NFCSIM_ERR(d, fmt, args...) nfc_err(&d->nfc_digital_dev->nfc_dev->dev, \
  17                                            "%s: " fmt, __func__, ## args)
  18
  19#define NFCSIM_DBG(d, fmt, args...) dev_dbg(&d->nfc_digital_dev->nfc_dev->dev, \
  20                                            "%s: " fmt, __func__, ## args)
  21
  22#define NFCSIM_VERSION "0.2"
  23
  24#define NFCSIM_MODE_NONE        0
  25#define NFCSIM_MODE_INITIATOR   1
  26#define NFCSIM_MODE_TARGET      2
  27
  28#define NFCSIM_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC   | \
  29                             NFC_DIGITAL_DRV_CAPS_TG_CRC)
  30
  31struct nfcsim {
  32        struct nfc_digital_dev *nfc_digital_dev;
  33
  34        struct work_struct recv_work;
  35        struct delayed_work send_work;
  36
  37        struct nfcsim_link *link_in;
  38        struct nfcsim_link *link_out;
  39
  40        bool up;
  41        u8 mode;
  42        u8 rf_tech;
  43
  44        u16 recv_timeout;
  45
  46        nfc_digital_cmd_complete_t cb;
  47        void *arg;
  48
  49        u8 dropframe;
  50};
  51
  52struct nfcsim_link {
  53        struct mutex lock;
  54
  55        u8 rf_tech;
  56        u8 mode;
  57
  58        u8 shutdown;
  59
  60        struct sk_buff *skb;
  61        wait_queue_head_t recv_wait;
  62        u8 cond;
  63};
  64
  65static struct nfcsim_link *nfcsim_link_new(void)
  66{
  67        struct nfcsim_link *link;
  68
  69        link = kzalloc(sizeof(struct nfcsim_link), GFP_KERNEL);
  70        if (!link)
  71                return NULL;
  72
  73        mutex_init(&link->lock);
  74        init_waitqueue_head(&link->recv_wait);
  75
  76        return link;
  77}
  78
  79static void nfcsim_link_free(struct nfcsim_link *link)
  80{
  81        dev_kfree_skb(link->skb);
  82        kfree(link);
  83}
  84
  85static void nfcsim_link_recv_wake(struct nfcsim_link *link)
  86{
  87        link->cond = 1;
  88        wake_up_interruptible(&link->recv_wait);
  89}
  90
  91static void nfcsim_link_set_skb(struct nfcsim_link *link, struct sk_buff *skb,
  92                                u8 rf_tech, u8 mode)
  93{
  94        mutex_lock(&link->lock);
  95
  96        dev_kfree_skb(link->skb);
  97        link->skb = skb;
  98        link->rf_tech = rf_tech;
  99        link->mode = mode;
 100
 101        mutex_unlock(&link->lock);
 102}
 103
 104static void nfcsim_link_recv_cancel(struct nfcsim_link *link)
 105{
 106        mutex_lock(&link->lock);
 107
 108        link->mode = NFCSIM_MODE_NONE;
 109
 110        mutex_unlock(&link->lock);
 111
 112        nfcsim_link_recv_wake(link);
 113}
 114
 115static void nfcsim_link_shutdown(struct nfcsim_link *link)
 116{
 117        mutex_lock(&link->lock);
 118
 119        link->shutdown = 1;
 120        link->mode = NFCSIM_MODE_NONE;
 121
 122        mutex_unlock(&link->lock);
 123
 124        nfcsim_link_recv_wake(link);
 125}
 126
 127static struct sk_buff *nfcsim_link_recv_skb(struct nfcsim_link *link,
 128                                            int timeout, u8 rf_tech, u8 mode)
 129{
 130        int rc;
 131        struct sk_buff *skb;
 132
 133        rc = wait_event_interruptible_timeout(link->recv_wait,
 134                                              link->cond,
 135                                              msecs_to_jiffies(timeout));
 136
 137        mutex_lock(&link->lock);
 138
 139        skb = link->skb;
 140        link->skb = NULL;
 141
 142        if (!rc) {
 143                rc = -ETIMEDOUT;
 144                goto done;
 145        }
 146
 147        if (!skb || link->rf_tech != rf_tech || link->mode == mode) {
 148                rc = -EINVAL;
 149                goto done;
 150        }
 151
 152        if (link->shutdown) {
 153                rc = -ENODEV;
 154                goto done;
 155        }
 156
 157done:
 158        mutex_unlock(&link->lock);
 159
 160        if (rc < 0) {
 161                dev_kfree_skb(skb);
 162                skb = ERR_PTR(rc);
 163        }
 164
 165        link->cond = 0;
 166
 167        return skb;
 168}
 169
 170static void nfcsim_send_wq(struct work_struct *work)
 171{
 172        struct nfcsim *dev = container_of(work, struct nfcsim, send_work.work);
 173
 174        /*
 175         * To effectively send data, the device just wake up its link_out which
 176         * is the link_in of the peer device. The exchanged skb has already been
 177         * stored in the dev->link_out through nfcsim_link_set_skb().
 178         */
 179        nfcsim_link_recv_wake(dev->link_out);
 180}
 181
 182static void nfcsim_recv_wq(struct work_struct *work)
 183{
 184        struct nfcsim *dev = container_of(work, struct nfcsim, recv_work);
 185        struct sk_buff *skb;
 186
 187        skb = nfcsim_link_recv_skb(dev->link_in, dev->recv_timeout,
 188                                   dev->rf_tech, dev->mode);
 189
 190        if (!dev->up) {
 191                NFCSIM_ERR(dev, "Device is down\n");
 192
 193                if (!IS_ERR(skb))
 194                        dev_kfree_skb(skb);
 195
 196                skb = ERR_PTR(-ENODEV);
 197        }
 198
 199        dev->cb(dev->nfc_digital_dev, dev->arg, skb);
 200}
 201
 202static int nfcsim_send(struct nfc_digital_dev *ddev, struct sk_buff *skb,
 203                       u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
 204{
 205        struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
 206        u8 delay;
 207
 208        if (!dev->up) {
 209                NFCSIM_ERR(dev, "Device is down\n");
 210                return -ENODEV;
 211        }
 212
 213        dev->recv_timeout = timeout;
 214        dev->cb = cb;
 215        dev->arg = arg;
 216
 217        schedule_work(&dev->recv_work);
 218
 219        if (dev->dropframe) {
 220                NFCSIM_DBG(dev, "dropping frame (out of %d)\n", dev->dropframe);
 221                dev_kfree_skb(skb);
 222                dev->dropframe--;
 223
 224                return 0;
 225        }
 226
 227        if (skb) {
 228                nfcsim_link_set_skb(dev->link_out, skb, dev->rf_tech,
 229                                    dev->mode);
 230
 231                /* Add random delay (between 3 and 10 ms) before sending data */
 232                get_random_bytes(&delay, 1);
 233                delay = 3 + (delay & 0x07);
 234
 235                schedule_delayed_work(&dev->send_work, msecs_to_jiffies(delay));
 236        }
 237
 238        return 0;
 239}
 240
 241static void nfcsim_abort_cmd(struct nfc_digital_dev *ddev)
 242{
 243        struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
 244
 245        nfcsim_link_recv_cancel(dev->link_in);
 246}
 247
 248static int nfcsim_switch_rf(struct nfc_digital_dev *ddev, bool on)
 249{
 250        struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
 251
 252        dev->up = on;
 253
 254        return 0;
 255}
 256
 257static int nfcsim_in_configure_hw(struct nfc_digital_dev *ddev,
 258                                          int type, int param)
 259{
 260        struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
 261
 262        switch (type) {
 263        case NFC_DIGITAL_CONFIG_RF_TECH:
 264                dev->up = true;
 265                dev->mode = NFCSIM_MODE_INITIATOR;
 266                dev->rf_tech = param;
 267                break;
 268
 269        case NFC_DIGITAL_CONFIG_FRAMING:
 270                break;
 271
 272        default:
 273                NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type);
 274                return -EINVAL;
 275        }
 276
 277        return 0;
 278}
 279
 280static int nfcsim_in_send_cmd(struct nfc_digital_dev *ddev,
 281                               struct sk_buff *skb, u16 timeout,
 282                               nfc_digital_cmd_complete_t cb, void *arg)
 283{
 284        return nfcsim_send(ddev, skb, timeout, cb, arg);
 285}
 286
 287static int nfcsim_tg_configure_hw(struct nfc_digital_dev *ddev,
 288                                          int type, int param)
 289{
 290        struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
 291
 292        switch (type) {
 293        case NFC_DIGITAL_CONFIG_RF_TECH:
 294                dev->up = true;
 295                dev->mode = NFCSIM_MODE_TARGET;
 296                dev->rf_tech = param;
 297                break;
 298
 299        case NFC_DIGITAL_CONFIG_FRAMING:
 300                break;
 301
 302        default:
 303                NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type);
 304                return -EINVAL;
 305        }
 306
 307        return 0;
 308}
 309
 310static int nfcsim_tg_send_cmd(struct nfc_digital_dev *ddev,
 311                               struct sk_buff *skb, u16 timeout,
 312                               nfc_digital_cmd_complete_t cb, void *arg)
 313{
 314        return nfcsim_send(ddev, skb, timeout, cb, arg);
 315}
 316
 317static int nfcsim_tg_listen(struct nfc_digital_dev *ddev, u16 timeout,
 318                            nfc_digital_cmd_complete_t cb, void *arg)
 319{
 320        return nfcsim_send(ddev, NULL, timeout, cb, arg);
 321}
 322
 323static struct nfc_digital_ops nfcsim_digital_ops = {
 324        .in_configure_hw = nfcsim_in_configure_hw,
 325        .in_send_cmd = nfcsim_in_send_cmd,
 326
 327        .tg_listen = nfcsim_tg_listen,
 328        .tg_configure_hw = nfcsim_tg_configure_hw,
 329        .tg_send_cmd = nfcsim_tg_send_cmd,
 330
 331        .abort_cmd = nfcsim_abort_cmd,
 332        .switch_rf = nfcsim_switch_rf,
 333};
 334
 335static struct dentry *nfcsim_debugfs_root;
 336
 337static void nfcsim_debugfs_init(void)
 338{
 339        nfcsim_debugfs_root = debugfs_create_dir("nfcsim", NULL);
 340
 341        if (!nfcsim_debugfs_root)
 342                pr_err("Could not create debugfs entry\n");
 343
 344}
 345
 346static void nfcsim_debugfs_remove(void)
 347{
 348        debugfs_remove_recursive(nfcsim_debugfs_root);
 349}
 350
 351static void nfcsim_debugfs_init_dev(struct nfcsim *dev)
 352{
 353        struct dentry *dev_dir;
 354        char devname[5]; /* nfcX\0 */
 355        u32 idx;
 356        int n;
 357
 358        if (!nfcsim_debugfs_root) {
 359                NFCSIM_ERR(dev, "nfcsim debugfs not initialized\n");
 360                return;
 361        }
 362
 363        idx = dev->nfc_digital_dev->nfc_dev->idx;
 364        n = snprintf(devname, sizeof(devname), "nfc%d", idx);
 365        if (n >= sizeof(devname)) {
 366                NFCSIM_ERR(dev, "Could not compute dev name for dev %d\n", idx);
 367                return;
 368        }
 369
 370        dev_dir = debugfs_create_dir(devname, nfcsim_debugfs_root);
 371        if (!dev_dir) {
 372                NFCSIM_ERR(dev, "Could not create debugfs entries for nfc%d\n",
 373                           idx);
 374                return;
 375        }
 376
 377        debugfs_create_u8("dropframe", 0664, dev_dir, &dev->dropframe);
 378}
 379
 380static struct nfcsim *nfcsim_device_new(struct nfcsim_link *link_in,
 381                                        struct nfcsim_link *link_out)
 382{
 383        struct nfcsim *dev;
 384        int rc;
 385
 386        dev = kzalloc(sizeof(struct nfcsim), GFP_KERNEL);
 387        if (!dev)
 388                return ERR_PTR(-ENOMEM);
 389
 390        INIT_DELAYED_WORK(&dev->send_work, nfcsim_send_wq);
 391        INIT_WORK(&dev->recv_work, nfcsim_recv_wq);
 392
 393        dev->nfc_digital_dev =
 394                        nfc_digital_allocate_device(&nfcsim_digital_ops,
 395                                                    NFC_PROTO_NFC_DEP_MASK,
 396                                                    NFCSIM_CAPABILITIES,
 397                                                    0, 0);
 398        if (!dev->nfc_digital_dev) {
 399                kfree(dev);
 400                return ERR_PTR(-ENOMEM);
 401        }
 402
 403        nfc_digital_set_drvdata(dev->nfc_digital_dev, dev);
 404
 405        dev->link_in = link_in;
 406        dev->link_out = link_out;
 407
 408        rc = nfc_digital_register_device(dev->nfc_digital_dev);
 409        if (rc) {
 410                pr_err("Could not register digital device (%d)\n", rc);
 411                nfc_digital_free_device(dev->nfc_digital_dev);
 412                kfree(dev);
 413
 414                return ERR_PTR(rc);
 415        }
 416
 417        nfcsim_debugfs_init_dev(dev);
 418
 419        return dev;
 420}
 421
 422static void nfcsim_device_free(struct nfcsim *dev)
 423{
 424        nfc_digital_unregister_device(dev->nfc_digital_dev);
 425
 426        dev->up = false;
 427
 428        nfcsim_link_shutdown(dev->link_in);
 429
 430        cancel_delayed_work_sync(&dev->send_work);
 431        cancel_work_sync(&dev->recv_work);
 432
 433        nfc_digital_free_device(dev->nfc_digital_dev);
 434
 435        kfree(dev);
 436}
 437
 438static struct nfcsim *dev0;
 439static struct nfcsim *dev1;
 440
 441static int __init nfcsim_init(void)
 442{
 443        struct nfcsim_link *link0, *link1;
 444        int rc;
 445
 446        link0 = nfcsim_link_new();
 447        link1 = nfcsim_link_new();
 448        if (!link0 || !link1) {
 449                rc = -ENOMEM;
 450                goto exit_err;
 451        }
 452
 453        nfcsim_debugfs_init();
 454
 455        dev0 = nfcsim_device_new(link0, link1);
 456        if (IS_ERR(dev0)) {
 457                rc = PTR_ERR(dev0);
 458                goto exit_err;
 459        }
 460
 461        dev1 = nfcsim_device_new(link1, link0);
 462        if (IS_ERR(dev1)) {
 463                nfcsim_device_free(dev0);
 464
 465                rc = PTR_ERR(dev1);
 466                goto exit_err;
 467        }
 468
 469        pr_info("nfcsim " NFCSIM_VERSION " initialized\n");
 470
 471        return 0;
 472
 473exit_err:
 474        pr_err("Failed to initialize nfcsim driver (%d)\n", rc);
 475
 476        if (link0)
 477                nfcsim_link_free(link0);
 478        if (link1)
 479                nfcsim_link_free(link1);
 480
 481        return rc;
 482}
 483
 484static void __exit nfcsim_exit(void)
 485{
 486        struct nfcsim_link *link0, *link1;
 487
 488        link0 = dev0->link_in;
 489        link1 = dev0->link_out;
 490
 491        nfcsim_device_free(dev0);
 492        nfcsim_device_free(dev1);
 493
 494        nfcsim_link_free(link0);
 495        nfcsim_link_free(link1);
 496
 497        nfcsim_debugfs_remove();
 498}
 499
 500module_init(nfcsim_init);
 501module_exit(nfcsim_exit);
 502
 503MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION);
 504MODULE_VERSION(NFCSIM_VERSION);
 505MODULE_LICENSE("GPL");
 506