e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 1) // SPDX-License-Identifier: GPL-2.0-or-later
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 2) /*
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 3) * Virtual NCI device simulation driver
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 4) *
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 5) * Copyright (C) 2020 Samsung Electrnoics
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 6) * Bongsu Jeon <bongsu.jeon@samsung.com>
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 7) */
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 8)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 9) #include <linux/kernel.h>
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 10) #include <linux/module.h>
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 11) #include <linux/miscdevice.h>
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 12) #include <linux/mutex.h>
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 13) #include <net/nfc/nci_core.h>
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 14)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 15) enum virtual_ncidev_mode {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 16) virtual_ncidev_enabled,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 17) virtual_ncidev_disabled,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 18) virtual_ncidev_disabling,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 19) };
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 20)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 21) #define IOCTL_GET_NCIDEV_IDX 0
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 22) #define VIRTUAL_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 23) NFC_PROTO_MIFARE_MASK | \
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 24) NFC_PROTO_FELICA_MASK | \
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 25) NFC_PROTO_ISO14443_MASK | \
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 26) NFC_PROTO_ISO14443_B_MASK | \
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 27) NFC_PROTO_ISO15693_MASK)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 28)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 29) static enum virtual_ncidev_mode state;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 30) static struct miscdevice miscdev;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 31) static struct sk_buff *send_buff;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 32) static struct nci_dev *ndev;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 33) static DEFINE_MUTEX(nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 34)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 35) static int virtual_nci_open(struct nci_dev *ndev)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 36) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 37) return 0;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 38) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 39)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 40) static int virtual_nci_close(struct nci_dev *ndev)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 41) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 42) mutex_lock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 43) kfree_skb(send_buff);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 44) send_buff = NULL;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 45) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 46)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 47) return 0;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 48) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 49)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 50) static int virtual_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 51) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 52) mutex_lock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 53) if (state != virtual_ncidev_enabled) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 54) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 55) return 0;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 56) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 57)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 58) if (send_buff) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 59) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 60) return -1;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 61) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 62) send_buff = skb_copy(skb, GFP_KERNEL);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 63) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 64)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 65) return 0;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 66) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 67)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 68) static struct nci_ops virtual_nci_ops = {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 69) .open = virtual_nci_open,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 70) .close = virtual_nci_close,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 71) .send = virtual_nci_send
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 72) };
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 73)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 74) static ssize_t virtual_ncidev_read(struct file *file, char __user *buf,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 75) size_t count, loff_t *ppos)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 76) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 77) size_t actual_len;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 78)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 79) mutex_lock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 80) if (!send_buff) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 81) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 82) return 0;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 83) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 84)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 85) actual_len = min_t(size_t, count, send_buff->len);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 86)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 87) if (copy_to_user(buf, send_buff->data, actual_len)) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 88) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 89) return -EFAULT;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 90) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 91)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 92) skb_pull(send_buff, actual_len);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 93) if (send_buff->len == 0) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 94) consume_skb(send_buff);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 95) send_buff = NULL;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 96) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 97) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 98)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 99) return actual_len;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 100) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 101)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 102) static ssize_t virtual_ncidev_write(struct file *file,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 103) const char __user *buf,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 104) size_t count, loff_t *ppos)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 105) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 106) struct sk_buff *skb;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 107)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 108) skb = alloc_skb(count, GFP_KERNEL);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 109) if (!skb)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 110) return -ENOMEM;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 111)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 112) if (copy_from_user(skb_put(skb, count), buf, count)) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 113) kfree_skb(skb);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 114) return -EFAULT;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 115) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 116)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 117) nci_recv_frame(ndev, skb);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 118) return count;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 119) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 120)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 121) static int virtual_ncidev_open(struct inode *inode, struct file *file)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 122) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 123) int ret = 0;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 124)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 125) mutex_lock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 126) if (state != virtual_ncidev_disabled) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 127) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 128) return -EBUSY;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 129) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 130)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 131) ndev = nci_allocate_device(&virtual_nci_ops, VIRTUAL_NFC_PROTOCOLS,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 132) 0, 0);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 133) if (!ndev) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 134) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 135) return -ENOMEM;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 136) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 137)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 138) ret = nci_register_device(ndev);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 139) if (ret < 0) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 140) nci_free_device(ndev);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 141) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 142) return ret;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 143) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 144) state = virtual_ncidev_enabled;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 145) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 146)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 147) return 0;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 148) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 149)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 150) static int virtual_ncidev_close(struct inode *inode, struct file *file)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 151) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 152) mutex_lock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 153)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 154) if (state == virtual_ncidev_enabled) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 155) state = virtual_ncidev_disabling;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 156) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 157)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 158) nci_unregister_device(ndev);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 159) nci_free_device(ndev);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 160)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 161) mutex_lock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 162) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 163)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 164) state = virtual_ncidev_disabled;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 165) mutex_unlock(&nci_mutex);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 166)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 167) return 0;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 168) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 169)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 170) static long virtual_ncidev_ioctl(struct file *flip, unsigned int cmd,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 171) unsigned long arg)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 172) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 173) struct nfc_dev *nfc_dev = ndev->nfc_dev;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 174) void __user *p = (void __user *)arg;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 175)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 176) if (cmd != IOCTL_GET_NCIDEV_IDX)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 177) return -ENOTTY;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 178)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 179) if (copy_to_user(p, &nfc_dev->idx, sizeof(nfc_dev->idx)))
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 180) return -EFAULT;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 181)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 182) return 0;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 183) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 184)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 185) static const struct file_operations virtual_ncidev_fops = {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 186) .owner = THIS_MODULE,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 187) .read = virtual_ncidev_read,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 188) .write = virtual_ncidev_write,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 189) .open = virtual_ncidev_open,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 190) .release = virtual_ncidev_close,
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 191) .unlocked_ioctl = virtual_ncidev_ioctl
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 192) };
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 193)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 194) static int __init virtual_ncidev_init(void)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 195) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 196) state = virtual_ncidev_disabled;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 197) miscdev.minor = MISC_DYNAMIC_MINOR;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 198) miscdev.name = "virtual_nci";
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 199) miscdev.fops = &virtual_ncidev_fops;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 200) miscdev.mode = S_IALLUGO;
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 201)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 202) return misc_register(&miscdev);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 203) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 204)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 205) static void __exit virtual_ncidev_exit(void)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 206) {
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 207) misc_deregister(&miscdev);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 208) }
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 209)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 210) module_init(virtual_ncidev_init);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 211) module_exit(virtual_ncidev_exit);
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 212)
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 213) MODULE_LICENSE("GPL");
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 214) MODULE_DESCRIPTION("Virtual NCI device simulation driver");
e624e6c3e777f (Bongsu Jeon 2021-01-27 22:08:28 +0900 215) MODULE_AUTHOR("Bongsu Jeon <bongsu.jeon@samsung.com>");