1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Virtual NCI device simulation driver
5 * Copyright (C) 2020 Samsung Electrnoics
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/miscdevice.h>
12 #include <linux/mutex.h>
13 #include <net/nfc/nci_core.h>
15 enum virtual_ncidev_mode {
16 virtual_ncidev_enabled,
17 virtual_ncidev_disabled,
18 virtual_ncidev_disabling,
21 #define IOCTL_GET_NCIDEV_IDX 0
22 #define VIRTUAL_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
23 NFC_PROTO_MIFARE_MASK | \
24 NFC_PROTO_FELICA_MASK | \
25 NFC_PROTO_ISO14443_MASK | \
26 NFC_PROTO_ISO14443_B_MASK | \
27 NFC_PROTO_ISO15693_MASK)
29 static enum virtual_ncidev_mode state;
30 static struct miscdevice miscdev;
31 static struct sk_buff *send_buff;
32 static struct nci_dev *ndev;
33 static DEFINE_MUTEX(nci_mutex);
35 static int virtual_nci_open(struct nci_dev *ndev)
40 static int virtual_nci_close(struct nci_dev *ndev)
42 mutex_lock(&nci_mutex);
45 mutex_unlock(&nci_mutex);
50 static int virtual_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
52 mutex_lock(&nci_mutex);
53 if (state != virtual_ncidev_enabled) {
54 mutex_unlock(&nci_mutex);
59 mutex_unlock(&nci_mutex);
62 send_buff = skb_copy(skb, GFP_KERNEL);
63 mutex_unlock(&nci_mutex);
68 static struct nci_ops virtual_nci_ops = {
69 .open = virtual_nci_open,
70 .close = virtual_nci_close,
71 .send = virtual_nci_send
74 static ssize_t virtual_ncidev_read(struct file *file, char __user *buf,
75 size_t count, loff_t *ppos)
79 mutex_lock(&nci_mutex);
81 mutex_unlock(&nci_mutex);
85 actual_len = min_t(size_t, count, send_buff->len);
87 if (copy_to_user(buf, send_buff->data, actual_len)) {
88 mutex_unlock(&nci_mutex);
92 skb_pull(send_buff, actual_len);
93 if (send_buff->len == 0) {
94 consume_skb(send_buff);
97 mutex_unlock(&nci_mutex);
102 static ssize_t virtual_ncidev_write(struct file *file,
103 const char __user *buf,
104 size_t count, loff_t *ppos)
108 skb = alloc_skb(count, GFP_KERNEL);
112 if (copy_from_user(skb_put(skb, count), buf, count)) {
117 nci_recv_frame(ndev, skb);
121 static int virtual_ncidev_open(struct inode *inode, struct file *file)
125 mutex_lock(&nci_mutex);
126 if (state != virtual_ncidev_disabled) {
127 mutex_unlock(&nci_mutex);
131 ndev = nci_allocate_device(&virtual_nci_ops, VIRTUAL_NFC_PROTOCOLS,
134 mutex_unlock(&nci_mutex);
138 ret = nci_register_device(ndev);
140 nci_free_device(ndev);
141 mutex_unlock(&nci_mutex);
144 state = virtual_ncidev_enabled;
145 mutex_unlock(&nci_mutex);
150 static int virtual_ncidev_close(struct inode *inode, struct file *file)
152 mutex_lock(&nci_mutex);
154 if (state == virtual_ncidev_enabled) {
155 state = virtual_ncidev_disabling;
156 mutex_unlock(&nci_mutex);
158 nci_unregister_device(ndev);
159 nci_free_device(ndev);
161 mutex_lock(&nci_mutex);
164 state = virtual_ncidev_disabled;
165 mutex_unlock(&nci_mutex);
170 static long virtual_ncidev_ioctl(struct file *flip, unsigned int cmd,
173 struct nfc_dev *nfc_dev = ndev->nfc_dev;
174 void __user *p = (void __user *)arg;
176 if (cmd != IOCTL_GET_NCIDEV_IDX)
179 if (copy_to_user(p, &nfc_dev->idx, sizeof(nfc_dev->idx)))
185 static const struct file_operations virtual_ncidev_fops = {
186 .owner = THIS_MODULE,
187 .read = virtual_ncidev_read,
188 .write = virtual_ncidev_write,
189 .open = virtual_ncidev_open,
190 .release = virtual_ncidev_close,
191 .unlocked_ioctl = virtual_ncidev_ioctl
194 static int __init virtual_ncidev_init(void)
196 state = virtual_ncidev_disabled;
197 miscdev.minor = MISC_DYNAMIC_MINOR;
198 miscdev.name = "virtual_nci";
199 miscdev.fops = &virtual_ncidev_fops;
200 miscdev.mode = S_IALLUGO;
202 return misc_register(&miscdev);
205 static void __exit virtual_ncidev_exit(void)
207 misc_deregister(&miscdev);
210 module_init(virtual_ncidev_init);
211 module_exit(virtual_ncidev_exit);
213 MODULE_LICENSE("GPL");
214 MODULE_DESCRIPTION("Virtual NCI device simulation driver");