cregit-Linux how code gets into the kernel

Release 4.14 drivers/nfc/nfcsim.c

Directory: drivers/nfc
/*
 * NFC hardware simulation driver
 * Copyright (c) 2013, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 */

#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ctype.h>
#include <linux/debugfs.h>
#include <linux/nfc.h>
#include <net/nfc/nfc.h>
#include <net/nfc/digital.h>


#define NFCSIM_ERR(d, fmt, args...) nfc_err(&d->nfc_digital_dev->nfc_dev->dev, \
                                            "%s: " fmt, __func__, ## args)


#define NFCSIM_DBG(d, fmt, args...) dev_dbg(&d->nfc_digital_dev->nfc_dev->dev, \
                                            "%s: " fmt, __func__, ## args)


#define NFCSIM_VERSION "0.2"


#define NFCSIM_MODE_NONE	0

#define NFCSIM_MODE_INITIATOR	1

#define NFCSIM_MODE_TARGET	2


#define NFCSIM_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC   | \
                             NFC_DIGITAL_DRV_CAPS_TG_CRC)


struct nfcsim {
	
struct nfc_digital_dev *nfc_digital_dev;

	
struct work_struct recv_work;
	
struct delayed_work send_work;

	
struct nfcsim_link *link_in;
	
struct nfcsim_link *link_out;

	
bool up;
	
u8 mode;
	
u8 rf_tech;

	
u16 recv_timeout;

	
nfc_digital_cmd_complete_t cb;
	
void *arg;

	
u8 dropframe;
};


struct nfcsim_link {
	
struct mutex lock;

	
u8 rf_tech;
	
u8 mode;

	
u8 shutdown;

	
struct sk_buff *skb;
	
wait_queue_head_t recv_wait;
	
u8 cond;
};


static struct nfcsim_link *nfcsim_link_new(void) { struct nfcsim_link *link; link = kzalloc(sizeof(struct nfcsim_link), GFP_KERNEL); if (!link) return NULL; mutex_init(&link->lock); init_waitqueue_head(&link->recv_wait); return link; }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande55100.00%2100.00%
Total55100.00%2100.00%


static void nfcsim_link_free(struct nfcsim_link *link) { dev_kfree_skb(link->skb); kfree(link); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande23100.00%2100.00%
Total23100.00%2100.00%


static void nfcsim_link_recv_wake(struct nfcsim_link *link) { link->cond = 1; wake_up_interruptible(&link->recv_wait); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande25100.00%2100.00%
Total25100.00%2100.00%


static void nfcsim_link_set_skb(struct nfcsim_link *link, struct sk_buff *skb, u8 rf_tech, u8 mode) { mutex_lock(&link->lock); dev_kfree_skb(link->skb); link->skb = skb; link->rf_tech = rf_tech; link->mode = mode; mutex_unlock(&link->lock); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande63100.00%2100.00%
Total63100.00%2100.00%


static void nfcsim_link_recv_cancel(struct nfcsim_link *link) { mutex_lock(&link->lock); link->mode = NFCSIM_MODE_NONE; mutex_unlock(&link->lock); nfcsim_link_recv_wake(link); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande38100.00%2100.00%
Total38100.00%2100.00%


static void nfcsim_link_shutdown(struct nfcsim_link *link) { mutex_lock(&link->lock); link->shutdown = 1; link->mode = NFCSIM_MODE_NONE; mutex_unlock(&link->lock); nfcsim_link_recv_wake(link); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande44100.00%2100.00%
Total44100.00%2100.00%


static struct sk_buff *nfcsim_link_recv_skb(struct nfcsim_link *link, int timeout, u8 rf_tech, u8 mode) { int rc; struct sk_buff *skb; rc = wait_event_interruptible_timeout(link->recv_wait, link->cond, msecs_to_jiffies(timeout)); mutex_lock(&link->lock); skb = link->skb; link->skb = NULL; if (!rc) { rc = -ETIMEDOUT; goto done; } if (!skb || link->rf_tech != rf_tech || link->mode == mode) { rc = -EINVAL; goto done; } if (link->shutdown) { rc = -ENODEV; goto done; } done: mutex_unlock(&link->lock); if (rc < 0) { dev_kfree_skb(skb); skb = ERR_PTR(rc); } link->cond = 0; return skb; }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande165100.00%2100.00%
Total165100.00%2100.00%


static void nfcsim_send_wq(struct work_struct *work) { struct nfcsim *dev = container_of(work, struct nfcsim, send_work.work); /* * To effectively send data, the device just wake up its link_out which * is the link_in of the peer device. The exchanged skb has already been * stored in the dev->link_out through nfcsim_link_set_skb(). */ nfcsim_link_recv_wake(dev->link_out); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande36100.00%2100.00%
Total36100.00%2100.00%


static void nfcsim_recv_wq(struct work_struct *work) { struct nfcsim *dev = container_of(work, struct nfcsim, recv_work); struct sk_buff *skb; skb = nfcsim_link_recv_skb(dev->link_in, dev->recv_timeout, dev->rf_tech, dev->mode); if (!dev->up) { NFCSIM_ERR(dev, "Device is down\n"); if (!IS_ERR(skb)) dev_kfree_skb(skb); skb = ERR_PTR(-ENODEV); } dev->cb(dev->nfc_digital_dev, dev->arg, skb); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande104100.00%2100.00%
Total104100.00%2100.00%


static int nfcsim_send(struct nfc_digital_dev *ddev, struct sk_buff *skb, u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) { struct nfcsim *dev = nfc_digital_get_drvdata(ddev); u8 delay; if (!dev->up) { NFCSIM_ERR(dev, "Device is down\n"); return -ENODEV; } dev->recv_timeout = timeout; dev->cb = cb; dev->arg = arg; schedule_work(&dev->recv_work); if (dev->dropframe) { NFCSIM_DBG(dev, "dropping frame (out of %d)\n", dev->dropframe); dev_kfree_skb(skb); dev->dropframe--; return 0; } if (skb) { nfcsim_link_set_skb(dev->link_out, skb, dev->rf_tech, dev->mode); /* Add random delay (between 3 and 10 ms) before sending data */ get_random_bytes(&delay, 1); delay = 3 + (delay & 0x07); schedule_delayed_work(&dev->send_work, msecs_to_jiffies(delay)); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande175100.00%3100.00%
Total175100.00%3100.00%


static void nfcsim_abort_cmd(struct nfc_digital_dev *ddev) { struct nfcsim *dev = nfc_digital_get_drvdata(ddev); nfcsim_link_recv_cancel(dev->link_in); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande28100.00%2100.00%
Total28100.00%2100.00%


static int nfcsim_switch_rf(struct nfc_digital_dev *ddev, bool on) { struct nfcsim *dev = nfc_digital_get_drvdata(ddev); dev->up = on; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande33100.00%2100.00%
Total33100.00%2100.00%


static int nfcsim_in_configure_hw(struct nfc_digital_dev *ddev, int type, int param) { struct nfcsim *dev = nfc_digital_get_drvdata(ddev); switch (type) { case NFC_DIGITAL_CONFIG_RF_TECH: dev->up = true; dev->mode = NFCSIM_MODE_INITIATOR; dev->rf_tech = param; break; case NFC_DIGITAL_CONFIG_FRAMING: break; default: NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type); return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande76100.00%2100.00%
Total76100.00%2100.00%


static int nfcsim_in_send_cmd(struct nfc_digital_dev *ddev, struct sk_buff *skb, u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) { return nfcsim_send(ddev, skb, timeout, cb, arg); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande3997.50%266.67%
Christophe Ricard12.50%133.33%
Total40100.00%3100.00%


static int nfcsim_tg_configure_hw(struct nfc_digital_dev *ddev, int type, int param) { struct nfcsim *dev = nfc_digital_get_drvdata(ddev); switch (type) { case NFC_DIGITAL_CONFIG_RF_TECH: dev->up = true; dev->mode = NFCSIM_MODE_TARGET; dev->rf_tech = param; break; case NFC_DIGITAL_CONFIG_FRAMING: break; default: NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type); return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande76100.00%2100.00%
Total76100.00%2100.00%


static int nfcsim_tg_send_cmd(struct nfc_digital_dev *ddev, struct sk_buff *skb, u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) { return nfcsim_send(ddev, skb, timeout, cb, arg); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande40100.00%2100.00%
Total40100.00%2100.00%


static int nfcsim_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) { return nfcsim_send(ddev, NULL, timeout, cb, arg); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande35100.00%2100.00%
Total35100.00%2100.00%

static struct nfc_digital_ops nfcsim_digital_ops = { .in_configure_hw = nfcsim_in_configure_hw, .in_send_cmd = nfcsim_in_send_cmd, .tg_listen = nfcsim_tg_listen, .tg_configure_hw = nfcsim_tg_configure_hw, .tg_send_cmd = nfcsim_tg_send_cmd, .abort_cmd = nfcsim_abort_cmd, .switch_rf = nfcsim_switch_rf, }; static struct dentry *nfcsim_debugfs_root;
static void nfcsim_debugfs_init(void) { nfcsim_debugfs_root = debugfs_create_dir("nfcsim", NULL); if (!nfcsim_debugfs_root) pr_err("Could not create debugfs entry\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande27100.00%1100.00%
Total27100.00%1100.00%


static void nfcsim_debugfs_remove(void) { debugfs_remove_recursive(nfcsim_debugfs_root); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande13100.00%1100.00%
Total13100.00%1100.00%


static void nfcsim_debugfs_init_dev(struct nfcsim *dev) { struct dentry *dev_dir; char devname[5]; /* nfcX\0 */ u32 idx; int n; if (!nfcsim_debugfs_root) { NFCSIM_ERR(dev, "nfcsim debugfs not initialized\n"); return; } idx = dev->nfc_digital_dev->nfc_dev->idx; n = snprintf(devname, sizeof(devname), "nfc%d", idx); if (n >= sizeof(devname)) { NFCSIM_ERR(dev, "Could not compute dev name for dev %d\n", idx); return; } dev_dir = debugfs_create_dir(devname, nfcsim_debugfs_root); if (!dev_dir) { NFCSIM_ERR(dev, "Could not create debugfs entries for nfc%d\n", idx); return; } debugfs_create_u8("dropframe", 0664, dev_dir, &dev->dropframe); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande131100.00%2100.00%
Total131100.00%2100.00%


static struct nfcsim *nfcsim_device_new(struct nfcsim_link *link_in, struct nfcsim_link *link_out) { struct nfcsim *dev; int rc; dev = kzalloc(sizeof(struct nfcsim), GFP_KERNEL); if (!dev) return ERR_PTR(-ENOMEM); INIT_DELAYED_WORK(&dev->send_work, nfcsim_send_wq); INIT_WORK(&dev->recv_work, nfcsim_recv_wq); dev->nfc_digital_dev = nfc_digital_allocate_device(&nfcsim_digital_ops, NFC_PROTO_NFC_DEP_MASK, NFCSIM_CAPABILITIES, 0, 0); if (!dev->nfc_digital_dev) { kfree(dev); return ERR_PTR(-ENOMEM); } nfc_digital_set_drvdata(dev->nfc_digital_dev, dev); dev->link_in = link_in; dev->link_out = link_out; rc = nfc_digital_register_device(dev->nfc_digital_dev); if (rc) { pr_err("Could not register digital device (%d)\n", rc); nfc_digital_free_device(dev->nfc_digital_dev); kfree(dev); return ERR_PTR(rc); } nfcsim_debugfs_init_dev(dev); return dev; }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande17899.44%375.00%
Saurabh Sengar10.56%125.00%
Total179100.00%4100.00%


static void nfcsim_device_free(struct nfcsim *dev) { nfc_digital_unregister_device(dev->nfc_digital_dev); dev->up = false; nfcsim_link_shutdown(dev->link_in); cancel_delayed_work_sync(&dev->send_work); cancel_work_sync(&dev->recv_work); nfc_digital_free_device(dev->nfc_digital_dev); kfree(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande59100.00%2100.00%
Total59100.00%2100.00%

static struct nfcsim *dev0; static struct nfcsim *dev1;
static int __init nfcsim_init(void) { struct nfcsim_link *link0, *link1; int rc; link0 = nfcsim_link_new(); link1 = nfcsim_link_new(); if (!link0 || !link1) { rc = -ENOMEM; goto exit_err; } nfcsim_debugfs_init(); dev0 = nfcsim_device_new(link0, link1); if (IS_ERR(dev0)) { rc = PTR_ERR(dev0); goto exit_err; } dev1 = nfcsim_device_new(link1, link0); if (IS_ERR(dev1)) { nfcsim_device_free(dev0); rc = PTR_ERR(dev1); goto exit_err; } pr_info("nfcsim " NFCSIM_VERSION " initialized\n"); return 0; exit_err: pr_err("Failed to initialize nfcsim driver (%d)\n", rc); if (link0) nfcsim_link_free(link0); if (link1) nfcsim_link_free(link1); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande14494.74%480.00%
Gustavo A. R. Silva85.26%120.00%
Total152100.00%5100.00%


static void __exit nfcsim_exit(void) { struct nfcsim_link *link0, *link1; link0 = dev0->link_in; link1 = dev0->link_out; nfcsim_device_free(dev0); nfcsim_device_free(dev1); nfcsim_link_free(link0); nfcsim_link_free(link1); nfcsim_debugfs_remove(); }

Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande52100.00%4100.00%
Total52100.00%4100.00%

module_init(nfcsim_init); module_exit(nfcsim_exit); MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION); MODULE_VERSION(NFCSIM_VERSION); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Thierry Escande189099.32%562.50%
Gustavo A. R. Silva80.42%112.50%
Saurabh Sengar40.21%112.50%
Christophe Ricard10.05%112.50%
Total1903100.00%8100.00%
Directory: drivers/nfc
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.