nfc: apply nfc driver
authormunkyu.im <munkyu.im@samsung.com>
Thu, 11 Jul 2013 15:34:01 +0000 (00:34 +0900)
committermunkyu.im <munkyu.im@samsung.com>
Thu, 11 Jul 2013 15:34:01 +0000 (00:34 +0900)
Signed-off-by: munkyu.im <munkyu.im@samsung.com>
drivers/maru/Kconfig
drivers/maru/Makefile
drivers/maru/maru_virtio_nfc.c [new file with mode: 0755]
include/linux/virtio_ids.h

index 9e80ddf320ff66a71a9d3290b427a8c5a7fb2fbb..954a1d1f587a0f896f82b8c4e443add4235f39bb 100644 (file)
@@ -75,3 +75,7 @@ config MARU_VIRTIO_EVDI
 config MARU_VIRTIO_SENSOR
        tristate "MARU VirtIO Virtual Sensor Device Driver"
        depends on MARU != n
+
+config MARU_VIRTIO_NFC
+       tristate "MARU VirtIO Virtual NFC Device Driver"
+       depends on MARU != n
index 0af73629e04a679d12d33acd2378ef0b31473055..ed0854d8d6355b4da1cc049436e297d412b5a75f 100644 (file)
@@ -15,3 +15,4 @@ obj-$(CONFIG_MARU_VIRTIO_KEYBOARD) += maru_virtio_keyboard.o
 obj-$(CONFIG_MARU_VIRTIO_ESM) += maru_virtio_esm.o
 obj-$(CONFIG_MARU_VIRTIO_EVDI) += maru_virtio_evdi.o
 obj-$(CONFIG_MARU_VIRTIO_EVDI) += maru_virtio_sensor.o
+obj-$(CONFIG_MARU_VIRTIO_NFC) += maru_virtio_nfc.o
diff --git a/drivers/maru/maru_virtio_nfc.c b/drivers/maru/maru_virtio_nfc.c
new file mode 100755 (executable)
index 0000000..2192c57
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Maru Virtio NFC Device Driver
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *  DaiYoung Kim <munkyu.im@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/sysfs.h>
+#include <linux/syscalls.h>
+#include <linux/fcntl.h>
+#include <asm/uaccess.h>
+#include <linux/file.h>
+
+#define DRIVER_NAME "NFC"
+
+#define LOG(fmt, ...) \
+       printk(KERN_ERR "%s: " fmt, DRIVER_NAME, ##__VA_ARGS__)
+
+#define CLASS_NAME             "network"
+#define DEVICE_NAME            "nfc"
+#define NFC_DATA_FILE "/sys/devices/virtual/network/nfc/data"
+
+/* device protocol */
+#define __MAX_BUF_SIZE 4096
+
+enum
+{
+       route_qemu = 0,
+       route_control_server = 1,
+       route_monitor = 2
+};
+
+enum request_cmd {
+       request_get = 0,
+       request_set,
+       request_answer
+};
+
+typedef unsigned int CSCliSN;
+
+struct msg_info {
+       char buf[__MAX_BUF_SIZE];
+
+       uint32_t route;
+       uint32_t use;
+       uint16_t count;
+       uint16_t index;
+
+       CSCliSN cclisn;
+};
+
+static struct device* device;
+
+static char data[PAGE_SIZE] = {0,};
+
+static ssize_t show_data(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       printk("NFC-[%s] \n", __FUNCTION__);
+       return snprintf(buf, PAGE_SIZE, "%s", data);
+}
+
+static ssize_t store_data(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       printk("NFC-[%s] \n", __FUNCTION__);
+    strncpy(data, buf, count);
+       return strnlen(buf, PAGE_SIZE);
+}
+
+static struct device_attribute da = __ATTR(data, 0644, show_data, store_data);
+
+/* device protocol */
+
+#define SIZEOF_MSG_INFO        sizeof(struct msg_info)
+
+struct virtio_nfc {
+       struct virtio_device* vdev;
+       struct virtqueue* rvq;
+       struct virtqueue* svq;
+
+       struct msg_info read_msginfo;
+       struct msg_info send_msginfo;
+
+       struct list_head read_list;
+       struct list_head write_list;
+
+       struct scatterlist sg_read[2];
+       struct scatterlist sg_send[2];
+
+    void *private;
+};
+
+struct virtio_nfc *vnfc;
+
+static struct virtio_device_id id_table[] = { { VIRTIO_ID_NFC,
+               VIRTIO_DEV_ANY_ID }, { 0 }, };
+
+static struct class* nfc_class;
+
+
+int make_buf_and_kick(void)
+{
+       int ret;
+       memset(&vnfc->read_msginfo, 0x00, sizeof(vnfc->read_msginfo));
+       ret = virtqueue_add_buf(vnfc->rvq, vnfc->sg_read, 0, 1, &vnfc->read_msginfo,
+                       GFP_ATOMIC );
+       if (ret < 0) {
+               LOG("failed to add buffer to virtqueue.(%d)\n", ret);
+               return ret;
+       }
+
+       virtqueue_kick(vnfc->rvq);
+
+       return 0;
+}
+
+static void write_file(char *filename, char *data, int len)
+{
+    struct file *file;
+    loff_t pos = 0;
+    int fd;
+
+    mm_segment_t old_fs = get_fs();
+    set_fs(KERNEL_DS);
+
+    fd = sys_open(filename, O_WRONLY|O_CREAT, 0644);
+    if (fd >= 0) {
+        sys_write(fd, data, strlen(data));
+        file = fget(fd);
+        if (file) {
+            vfs_write(file, data, len, &pos);
+            fput(file);
+            file_update_time(file);
+        }
+        sys_close(fd);
+    }
+    set_fs(old_fs);
+}
+
+static void nfc_recv_done(struct virtqueue *rvq) {
+
+       unsigned int len;
+       struct msg_info* msg;
+    int err;
+       msg = (struct msg_info*) virtqueue_get_buf(vnfc->rvq, &len);
+       if (msg == NULL ) {
+               LOG("failed to virtqueue_get_buf\n");
+               return;
+       }
+
+    if(msg->route == request_set) {
+        memset(data, 0x00, sizeof(data));
+        write_file(NFC_DATA_FILE, msg->buf, len);
+    }else if(msg->route == request_get) {
+       memset(&vnfc->send_msginfo, 0, sizeof(vnfc->send_msginfo));
+       vnfc->send_msginfo.route = request_answer;
+               strcpy(vnfc->send_msginfo.buf, data);
+        err = virtqueue_add_buf(vnfc->svq, vnfc->sg_send, 1, 0,        &vnfc->send_msginfo, GFP_ATOMIC);
+       if (err < 0) {
+               LOG("failed to add buffer to virtqueue (err = %d)", err);
+                   return;
+       }
+
+           virtqueue_kick(vnfc->svq);
+
+    }
+    
+       LOG("msg buf: %sroute: %d, len: %d", msg->buf, msg->route, msg->use);
+
+    make_buf_and_kick();
+}
+
+static void nfc_send_done(struct virtqueue *svq) {
+       unsigned int len = 0;
+
+       virtqueue_get_buf(svq, &len);
+}
+
+/*
+ *
+ */
+
+static int init_vqs(struct virtio_nfc *nfc) {
+       struct virtqueue *vqs[2];
+       vq_callback_t *callbacks[] = { nfc_recv_done, nfc_send_done };
+       const char *names[] = { "nfc_input", "nfc_output" };
+       int err;
+
+       err = nfc->vdev->config->find_vqs(nfc->vdev, 2, vqs, callbacks, names);
+       if (err < 0)
+               return err;
+
+       nfc->rvq = vqs[0];
+       nfc->svq = vqs[1];
+
+       return 0;
+}
+
+static int init_device(void)
+{
+       int ret;
+
+       nfc_class = class_create(THIS_MODULE, CLASS_NAME);
+
+       device = device_create(nfc_class, NULL, (dev_t)NULL, NULL, DEVICE_NAME);
+    if (device < 0) {
+                       LOG("NFC device creation is failed.");
+                       return -1;
+       }
+
+       ret = device_create_file(device, &da);
+       if (ret) {
+               device_destroy(nfc_class, (dev_t)NULL);
+           class_destroy(nfc_class);
+        return -1;
+    }
+
+       return 0;
+}
+
+
+static int nfc_probe(struct virtio_device* dev) {
+       int ret;
+
+       vnfc = kmalloc(sizeof(struct virtio_nfc), GFP_KERNEL);
+
+       INIT_LIST_HEAD(&vnfc->read_list);
+
+       vnfc->vdev = dev;
+       dev->priv = vnfc;
+
+       ret = init_device();
+       if (ret)
+       {
+               LOG("failed to _init_device\n");
+               return ret;
+       }
+       ret = init_vqs(vnfc);
+       if (ret) {
+               dev->config->del_vqs(dev);
+               kfree(vnfc);
+               dev->priv = NULL;
+
+               LOG("failed to init_vqs\n");
+               return ret;
+       }
+
+        /* enable callback */
+       virtqueue_enable_cb(vnfc->rvq);
+       virtqueue_enable_cb(vnfc->svq);
+
+       memset(&vnfc->read_msginfo, 0x00, sizeof(vnfc->read_msginfo));
+       sg_set_buf(vnfc->sg_read, &vnfc->read_msginfo, sizeof(struct msg_info));
+
+       memset(&vnfc->send_msginfo, 0x00, sizeof(vnfc->send_msginfo));
+       sg_set_buf(vnfc->sg_send, &vnfc->send_msginfo, sizeof(struct msg_info));
+
+
+       sg_init_one(vnfc->sg_read, &vnfc->read_msginfo, sizeof(vnfc->read_msginfo));
+       sg_init_one(vnfc->sg_send, &vnfc->send_msginfo, sizeof(vnfc->send_msginfo));
+
+    ret = make_buf_and_kick();
+       if (ret) {
+               dev->config->del_vqs(dev);
+               kfree(vnfc);
+               dev->priv = NULL;
+               LOG("failed to send buf");
+               return ret;
+       }
+
+       LOG("NFC Probe completed");
+       return 0;
+}
+
+static void __devexit nfc_remove(struct virtio_device* dev)
+{
+       struct virtio_nfc* _nfc = dev->priv;
+       if (!_nfc)
+       {
+               LOG("nfc is NULL\n");
+               return;
+       }
+
+       dev->config->reset(dev);
+       dev->config->del_vqs(dev);
+
+       kfree(_nfc);
+
+       LOG("driver is removed.\n");
+}
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+static struct virtio_driver virtio_nfc_driver = {
+               .driver = {
+                               .name = KBUILD_MODNAME,
+                               .owner = THIS_MODULE ,
+               },
+               .id_table = id_table,
+               .probe = nfc_probe,
+               .remove = nfc_remove,
+};
+
+static int __init nfc_init(void)
+{
+       LOG("NFC driver initialized.\n");
+
+       return register_virtio_driver(&virtio_nfc_driver);
+}
+
+static void __exit nfc_exit(void)
+{
+    device_destroy(nfc_class, (dev_t)NULL);
+
+    /*device_destroy(nfc_class, nfc_dev_number);*/
+
+    class_destroy(nfc_class);
+
+    unregister_virtio_driver(&virtio_nfc_driver);
+
+    LOG("NFC driver is destroyed.\n");
+}
+
+module_init(nfc_init);
+module_exit(nfc_exit);
+
+MODULE_LICENSE("GPL2");
+MODULE_AUTHOR("DaiYoung Kim <daiyoung777.kim@samsung.com>");
+MODULE_DESCRIPTION("Emulator Virtio EmulatorVirtualDeviceInterface Driver");
+
index 9b9833cedcfea9509285f241690f45fcc3040d93..c185ffbb460fa685b9b9c2187a839e8b2b2a7334 100755 (executable)
@@ -47,6 +47,7 @@
 #define VIRTIO_ID_HWKEY                14 /* virtio hwkey */
 #define VIRTIO_ID_EVDI         15 /* virtio evdi */
 #define VIRTIO_ID_SENSOR       16 /* virtio sensor */
+#define VIRTIO_ID_NFC          17 /* virtio NFC */
 
 #endif