linux/drivers/nfc/nfcsim.c
<<
>>
Prefs
   1/*
   2 * NFC hardware simulation driver
   3 * Copyright (c) 2013, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 */
  15
  16#include <linux/device.h>
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/nfc.h>
  20#include <net/nfc/nfc.h>
  21
  22#define DEV_ERR(_dev, fmt, args...) nfc_dev_err(&_dev->nfc_dev->dev, \
  23                                                "%s: " fmt, __func__, ## args)
  24
  25#define DEV_DBG(_dev, fmt, args...) nfc_dev_dbg(&_dev->nfc_dev->dev, \
  26                                                "%s: " fmt, __func__, ## args)
  27
  28#define NFCSIM_VERSION "0.1"
  29
  30#define NFCSIM_POLL_NONE        0
  31#define NFCSIM_POLL_INITIATOR   1
  32#define NFCSIM_POLL_TARGET      2
  33#define NFCSIM_POLL_DUAL        (NFCSIM_POLL_INITIATOR | NFCSIM_POLL_TARGET)
  34
  35struct nfcsim {
  36        struct nfc_dev *nfc_dev;
  37
  38        struct mutex lock;
  39
  40        struct delayed_work recv_work;
  41
  42        struct sk_buff *clone_skb;
  43
  44        struct delayed_work poll_work;
  45        u8 polling_mode;
  46        u8 curr_polling_mode;
  47
  48        u8 shutting_down;
  49
  50        u8 up;
  51
  52        u8 initiator;
  53
  54        data_exchange_cb_t cb;
  55        void *cb_context;
  56
  57        struct nfcsim *peer_dev;
  58};
  59
  60static struct nfcsim *dev0;
  61static struct nfcsim *dev1;
  62
  63static struct workqueue_struct *wq;
  64
  65static void nfcsim_cleanup_dev(struct nfcsim *dev, u8 shutdown)
  66{
  67        DEV_DBG(dev, "shutdown=%d", shutdown);
  68
  69        mutex_lock(&dev->lock);
  70
  71        dev->polling_mode = NFCSIM_POLL_NONE;
  72        dev->shutting_down = shutdown;
  73        dev->cb = NULL;
  74        dev_kfree_skb(dev->clone_skb);
  75        dev->clone_skb = NULL;
  76
  77        mutex_unlock(&dev->lock);
  78
  79        cancel_delayed_work_sync(&dev->poll_work);
  80        cancel_delayed_work_sync(&dev->recv_work);
  81}
  82
  83static int nfcsim_target_found(struct nfcsim *dev)
  84{
  85        struct nfc_target nfc_tgt;
  86
  87        DEV_DBG(dev, "");
  88
  89        memset(&nfc_tgt, 0, sizeof(struct nfc_target));
  90
  91        nfc_tgt.supported_protocols = NFC_PROTO_NFC_DEP_MASK;
  92        nfc_targets_found(dev->nfc_dev, &nfc_tgt, 1);
  93
  94        return 0;
  95}
  96
  97static int nfcsim_dev_up(struct nfc_dev *nfc_dev)
  98{
  99        struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
 100
 101        DEV_DBG(dev, "");
 102
 103        mutex_lock(&dev->lock);
 104
 105        dev->up = 1;
 106
 107        mutex_unlock(&dev->lock);
 108
 109        return 0;
 110}
 111
 112static int nfcsim_dev_down(struct nfc_dev *nfc_dev)
 113{
 114        struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
 115
 116        DEV_DBG(dev, "");
 117
 118        mutex_lock(&dev->lock);
 119
 120        dev->up = 0;
 121
 122        mutex_unlock(&dev->lock);
 123
 124        return 0;
 125}
 126
 127static int nfcsim_dep_link_up(struct nfc_dev *nfc_dev,
 128                              struct nfc_target *target,
 129                              u8 comm_mode, u8 *gb, size_t gb_len)
 130{
 131        int rc;
 132        struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
 133        struct nfcsim *peer = dev->peer_dev;
 134        u8 *remote_gb;
 135        size_t remote_gb_len;
 136
 137        DEV_DBG(dev, "target_idx: %d, comm_mode: %d\n", target->idx, comm_mode);
 138
 139        mutex_lock(&peer->lock);
 140
 141        nfc_tm_activated(peer->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
 142                         NFC_COMM_ACTIVE, gb, gb_len);
 143
 144        remote_gb = nfc_get_local_general_bytes(peer->nfc_dev, &remote_gb_len);
 145        if (!remote_gb) {
 146                DEV_ERR(peer, "Can't get remote general bytes");
 147
 148                mutex_unlock(&peer->lock);
 149                return -EINVAL;
 150        }
 151
 152        mutex_unlock(&peer->lock);
 153
 154        mutex_lock(&dev->lock);
 155
 156        rc = nfc_set_remote_general_bytes(nfc_dev, remote_gb, remote_gb_len);
 157        if (rc) {
 158                DEV_ERR(dev, "Can't set remote general bytes");
 159                mutex_unlock(&dev->lock);
 160                return rc;
 161        }
 162
 163        rc = nfc_dep_link_is_up(nfc_dev, target->idx, NFC_COMM_ACTIVE,
 164                                NFC_RF_INITIATOR);
 165
 166        mutex_unlock(&dev->lock);
 167
 168        return rc;
 169}
 170
 171static int nfcsim_dep_link_down(struct nfc_dev *nfc_dev)
 172{
 173        struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
 174
 175        DEV_DBG(dev, "");
 176
 177        nfcsim_cleanup_dev(dev, 0);
 178
 179        return 0;
 180}
 181
 182static int nfcsim_start_poll(struct nfc_dev *nfc_dev,
 183                             u32 im_protocols, u32 tm_protocols)
 184{
 185        struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
 186        int rc;
 187
 188        mutex_lock(&dev->lock);
 189
 190        if (dev->polling_mode != NFCSIM_POLL_NONE) {
 191                DEV_ERR(dev, "Already in polling mode");
 192                rc = -EBUSY;
 193                goto exit;
 194        }
 195
 196        if (im_protocols & NFC_PROTO_NFC_DEP_MASK)
 197                dev->polling_mode |= NFCSIM_POLL_INITIATOR;
 198
 199        if (tm_protocols & NFC_PROTO_NFC_DEP_MASK)
 200                dev->polling_mode |= NFCSIM_POLL_TARGET;
 201
 202        if (dev->polling_mode == NFCSIM_POLL_NONE) {
 203                DEV_ERR(dev, "Unsupported polling mode");
 204                rc = -EINVAL;
 205                goto exit;
 206        }
 207
 208        dev->initiator = 0;
 209        dev->curr_polling_mode = NFCSIM_POLL_NONE;
 210
 211        queue_delayed_work(wq, &dev->poll_work, 0);
 212
 213        DEV_DBG(dev, "Start polling: im: 0x%X, tm: 0x%X", im_protocols,
 214                tm_protocols);
 215
 216        rc = 0;
 217exit:
 218        mutex_unlock(&dev->lock);
 219
 220        return rc;
 221}
 222
 223static void nfcsim_stop_poll(struct nfc_dev *nfc_dev)
 224{
 225        struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
 226
 227        DEV_DBG(dev, "Stop poll");
 228
 229        mutex_lock(&dev->lock);
 230
 231        dev->polling_mode = NFCSIM_POLL_NONE;
 232
 233        mutex_unlock(&dev->lock);
 234
 235        cancel_delayed_work_sync(&dev->poll_work);
 236}
 237
 238static int nfcsim_activate_target(struct nfc_dev *nfc_dev,
 239                                  struct nfc_target *target, u32 protocol)
 240{
 241        struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
 242
 243        DEV_DBG(dev, "");
 244
 245        return -ENOTSUPP;
 246}
 247
 248static void nfcsim_deactivate_target(struct nfc_dev *nfc_dev,
 249                                     struct nfc_target *target)
 250{
 251        struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
 252
 253        DEV_DBG(dev, "");
 254}
 255
 256static void nfcsim_wq_recv(struct work_struct *work)
 257{
 258        struct nfcsim *dev = container_of(work, struct nfcsim,
 259                                          recv_work.work);
 260
 261        mutex_lock(&dev->lock);
 262
 263        if (dev->shutting_down || !dev->up || !dev->clone_skb) {
 264                dev_kfree_skb(dev->clone_skb);
 265                goto exit;
 266        }
 267
 268        if (dev->initiator) {
 269                if (!dev->cb) {
 270                        DEV_ERR(dev, "Null recv callback");
 271                        dev_kfree_skb(dev->clone_skb);
 272                        goto exit;
 273                }
 274
 275                dev->cb(dev->cb_context, dev->clone_skb, 0);
 276                dev->cb = NULL;
 277        } else {
 278                nfc_tm_data_received(dev->nfc_dev, dev->clone_skb);
 279        }
 280
 281exit:
 282        dev->clone_skb = NULL;
 283
 284        mutex_unlock(&dev->lock);
 285}
 286
 287static int nfcsim_tx(struct nfc_dev *nfc_dev, struct nfc_target *target,
 288                     struct sk_buff *skb, data_exchange_cb_t cb,
 289                     void *cb_context)
 290{
 291        struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
 292        struct nfcsim *peer = dev->peer_dev;
 293        int err;
 294
 295        mutex_lock(&dev->lock);
 296
 297        if (dev->shutting_down || !dev->up) {
 298                mutex_unlock(&dev->lock);
 299                err = -ENODEV;
 300                goto exit;
 301        }
 302
 303        dev->cb = cb;
 304        dev->cb_context = cb_context;
 305
 306        mutex_unlock(&dev->lock);
 307
 308        mutex_lock(&peer->lock);
 309
 310        peer->clone_skb = skb_clone(skb, GFP_KERNEL);
 311
 312        if (!peer->clone_skb) {
 313                DEV_ERR(dev, "skb_clone failed");
 314                mutex_unlock(&peer->lock);
 315                err = -ENOMEM;
 316                goto exit;
 317        }
 318
 319        /* This simulates an arbitrary transmission delay between the 2 devices.
 320         * If packet transmission occurs immediately between them, we have a
 321         * non-stop flow of several tens of thousands SYMM packets per second
 322         * and a burning cpu.
 323         *
 324         * TODO: Add support for a sysfs entry to control this delay.
 325         */
 326        queue_delayed_work(wq, &peer->recv_work, msecs_to_jiffies(5));
 327
 328        mutex_unlock(&peer->lock);
 329
 330        err = 0;
 331exit:
 332        dev_kfree_skb(skb);
 333
 334        return err;
 335}
 336
 337static int nfcsim_im_transceive(struct nfc_dev *nfc_dev,
 338                                struct nfc_target *target, struct sk_buff *skb,
 339                                data_exchange_cb_t cb, void *cb_context)
 340{
 341        return nfcsim_tx(nfc_dev, target, skb, cb, cb_context);
 342}
 343
 344static int nfcsim_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
 345{
 346        return nfcsim_tx(nfc_dev, NULL, skb, NULL, NULL);
 347}
 348
 349static struct nfc_ops nfcsim_nfc_ops = {
 350        .dev_up = nfcsim_dev_up,
 351        .dev_down = nfcsim_dev_down,
 352        .dep_link_up = nfcsim_dep_link_up,
 353        .dep_link_down = nfcsim_dep_link_down,
 354        .start_poll = nfcsim_start_poll,
 355        .stop_poll = nfcsim_stop_poll,
 356        .activate_target = nfcsim_activate_target,
 357        .deactivate_target = nfcsim_deactivate_target,
 358        .im_transceive = nfcsim_im_transceive,
 359        .tm_send = nfcsim_tm_send,
 360};
 361
 362static void nfcsim_set_polling_mode(struct nfcsim *dev)
 363{
 364        if (dev->polling_mode == NFCSIM_POLL_NONE) {
 365                dev->curr_polling_mode = NFCSIM_POLL_NONE;
 366                return;
 367        }
 368
 369        if (dev->curr_polling_mode == NFCSIM_POLL_NONE) {
 370                if (dev->polling_mode & NFCSIM_POLL_INITIATOR)
 371                        dev->curr_polling_mode = NFCSIM_POLL_INITIATOR;
 372                else
 373                        dev->curr_polling_mode = NFCSIM_POLL_TARGET;
 374
 375                return;
 376        }
 377
 378        if (dev->polling_mode == NFCSIM_POLL_DUAL) {
 379                if (dev->curr_polling_mode == NFCSIM_POLL_TARGET)
 380                        dev->curr_polling_mode = NFCSIM_POLL_INITIATOR;
 381                else
 382                        dev->curr_polling_mode = NFCSIM_POLL_TARGET;
 383        }
 384}
 385
 386static void nfcsim_wq_poll(struct work_struct *work)
 387{
 388        struct nfcsim *dev = container_of(work, struct nfcsim, poll_work.work);
 389        struct nfcsim *peer = dev->peer_dev;
 390
 391        /* These work items run on an ordered workqueue and are therefore
 392         * serialized. So we can take both mutexes without being dead locked.
 393         */
 394        mutex_lock(&dev->lock);
 395        mutex_lock(&peer->lock);
 396
 397        nfcsim_set_polling_mode(dev);
 398
 399        if (dev->curr_polling_mode == NFCSIM_POLL_NONE) {
 400                DEV_DBG(dev, "Not polling");
 401                goto unlock;
 402        }
 403
 404        DEV_DBG(dev, "Polling as %s",
 405                dev->curr_polling_mode == NFCSIM_POLL_INITIATOR ?
 406                "initiator" : "target");
 407
 408        if (dev->curr_polling_mode == NFCSIM_POLL_TARGET)
 409                goto sched_work;
 410
 411        if (peer->curr_polling_mode == NFCSIM_POLL_TARGET) {
 412                peer->polling_mode = NFCSIM_POLL_NONE;
 413                dev->polling_mode = NFCSIM_POLL_NONE;
 414
 415                dev->initiator = 1;
 416
 417                nfcsim_target_found(dev);
 418
 419                goto unlock;
 420        }
 421
 422sched_work:
 423        /* This defines the delay for an initiator to check if the other device
 424         * is polling in target mode.
 425         * If the device starts in dual mode polling, it switches between
 426         * initiator and target at every round.
 427         * Because the wq is ordered and only 1 work item is executed at a time,
 428         * we'll always have one device polling as initiator and the other as
 429         * target at some point, even if both are started in dual mode.
 430         */
 431        queue_delayed_work(wq, &dev->poll_work, msecs_to_jiffies(200));
 432
 433unlock:
 434        mutex_unlock(&peer->lock);
 435        mutex_unlock(&dev->lock);
 436}
 437
 438static struct nfcsim *nfcsim_init_dev(void)
 439{
 440        struct nfcsim *dev;
 441        int rc = -ENOMEM;
 442
 443        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 444        if (dev == NULL)
 445                return ERR_PTR(-ENOMEM);
 446
 447        mutex_init(&dev->lock);
 448
 449        INIT_DELAYED_WORK(&dev->recv_work, nfcsim_wq_recv);
 450        INIT_DELAYED_WORK(&dev->poll_work, nfcsim_wq_poll);
 451
 452        dev->nfc_dev = nfc_allocate_device(&nfcsim_nfc_ops,
 453                                           NFC_PROTO_NFC_DEP_MASK,
 454                                           0, 0);
 455        if (!dev->nfc_dev)
 456                goto error;
 457
 458        nfc_set_drvdata(dev->nfc_dev, dev);
 459
 460        rc = nfc_register_device(dev->nfc_dev);
 461        if (rc)
 462                goto free_nfc_dev;
 463
 464        return dev;
 465
 466free_nfc_dev:
 467        nfc_free_device(dev->nfc_dev);
 468
 469error:
 470        kfree(dev);
 471
 472        return ERR_PTR(rc);
 473}
 474
 475static void nfcsim_free_device(struct nfcsim *dev)
 476{
 477        nfc_unregister_device(dev->nfc_dev);
 478
 479        nfc_free_device(dev->nfc_dev);
 480
 481        kfree(dev);
 482}
 483
 484static int __init nfcsim_init(void)
 485{
 486        int rc;
 487
 488        /* We need an ordered wq to ensure that poll_work items are executed
 489         * one at a time.
 490         */
 491        wq = alloc_ordered_workqueue("nfcsim", 0);
 492        if (!wq) {
 493                rc = -ENOMEM;
 494                goto exit;
 495        }
 496
 497        dev0 = nfcsim_init_dev();
 498        if (IS_ERR(dev0)) {
 499                rc = PTR_ERR(dev0);
 500                goto exit;
 501        }
 502
 503        dev1 = nfcsim_init_dev();
 504        if (IS_ERR(dev1)) {
 505                kfree(dev0);
 506
 507                rc = PTR_ERR(dev1);
 508                goto exit;
 509        }
 510
 511        dev0->peer_dev = dev1;
 512        dev1->peer_dev = dev0;
 513
 514        pr_debug("NFCsim " NFCSIM_VERSION " initialized\n");
 515
 516        rc = 0;
 517exit:
 518        if (rc)
 519                pr_err("Failed to initialize nfcsim driver (%d)\n",
 520                       rc);
 521
 522        return rc;
 523}
 524
 525static void __exit nfcsim_exit(void)
 526{
 527        nfcsim_cleanup_dev(dev0, 1);
 528        nfcsim_cleanup_dev(dev1, 1);
 529
 530        nfcsim_free_device(dev0);
 531        nfcsim_free_device(dev1);
 532
 533        destroy_workqueue(wq);
 534}
 535
 536module_init(nfcsim_init);
 537module_exit(nfcsim_exit);
 538
 539MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION);
 540MODULE_VERSION(NFCSIM_VERSION);
 541MODULE_LICENSE("GPL");
 542
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.