hwkey: added Maru virtio hwkey driver
authorGiWoong Kim <giwoong.kim@samsung.com>
Thu, 9 Jan 2014 03:14:24 +0000 (12:14 +0900)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Thu, 27 Feb 2014 06:26:49 +0000 (15:26 +0900)
Change-Id: I90f8409eb62c2b52f9c9787f88d3df450ca4db45
Signed-off-by: GiWoong Kim <giwoong.kim@samsung.com>
arch/x86/configs/i386_tizen_emul_defconfig
drivers/maru/Kconfig
drivers/maru/Makefile
drivers/maru/maru_virtio_hwkey.c [new file with mode: 0644]

index 079027e..da89e93 100644 (file)
@@ -2807,8 +2807,13 @@ CONFIG_IOMMU_SUPPORT=y
 # CONFIG_PWM is not set
 # CONFIG_IPACK_BUS is not set
 # CONFIG_RESET_CONTROLLER is not set
+
+#
+# Maru
+#
 CONFIG_MARU=y
 CONFIG_MARU_VIRTIO_TOUCHSCREEN=y
+CONFIG_MARU_VIRTIO_HWKEY=y
 
 #
 # Firmware Drivers
index 528cd38..f8adb6a 100644 (file)
@@ -6,3 +6,7 @@ config MARU_VIRTIO_TOUCHSCREEN
        tristate "MARU Virtio Touchscreen Driver"
        depends on MARU != n
 
+config MARU_VIRTIO_HWKEY
+       tristate "MARU Virtio HW Key Driver"
+       depends on MARU != n
+
index 5d4bc40..ef9bc6c 100644 (file)
@@ -1 +1,2 @@
 obj-$(CONFIG_MARU_VIRTIO_TOUCHSCREEN) += maru_virtio_touchscreen.o
+obj-$(CONFIG_MARU_VIRTIO_HWKEY) += maru_virtio_hwkey.o
diff --git a/drivers/maru/maru_virtio_hwkey.c b/drivers/maru/maru_virtio_hwkey.c
new file mode 100644 (file)
index 0000000..c9f1ffb
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Maru Virtio Hwkey Device Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *  Sungmin Ha <sungmin82.ha@samsung.com>
+ *  Sangjin Kim <sangjin3.kim@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/fs.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/kthread.h>
+
+MODULE_LICENSE("GPL2");
+MODULE_AUTHOR("Sungmin Ha <sungmin82.ha@samsung.com>");
+MODULE_DESCRIPTION("Emulator Virtio Hwkey driver");
+
+#define DEVICE_NAME "virtio-hwkey"
+#define MAX_BUF_COUNT 64
+static int vqidx = 0;
+
+/* This structure must match the qemu definitions */
+typedef struct EmulHwkeyEvent {
+    uint8_t event_type;
+    uint32_t keycode;
+} EmulHwkeyEvent;
+
+typedef struct virtio_hwkey
+{
+    struct virtio_device *vdev;
+    struct virtqueue *vq;
+    struct input_dev *idev;
+
+    struct scatterlist sg[MAX_BUF_COUNT];
+    struct EmulHwkeyEvent vbuf[MAX_BUF_COUNT];
+
+    struct mutex event_mutex;
+} virtio_hwkey;
+
+virtio_hwkey *vh;
+
+static struct virtio_device_id id_table[] = {
+    { VIRTIO_ID_HWKEY, VIRTIO_DEV_ANY_ID },
+    { 0 },
+};
+
+/* keep it consistent with emulator-skin definition */
+enum {
+    KEY_PRESSED = 1,
+    KEY_RELEASED = 2,
+};
+
+static int err = 0;
+static unsigned int index = 0;
+
+/**
+* @brief : callback for virtqueue
+*/
+static void vq_hwkey_callback(struct virtqueue *vq)
+{
+    struct EmulHwkeyEvent hwkey_event;
+#if 0
+    printk(KERN_INFO "vq hwkey callback\n");
+#endif
+    while (1) {
+        memcpy(&hwkey_event, &vh->vbuf[vqidx], sizeof(hwkey_event));
+        if (hwkey_event.event_type == 0) {
+            break;
+        }
+        printk(KERN_ERR "keycode: %d, event_type: %d, vqidx: %d\n", hwkey_event.keycode, hwkey_event.event_type, vqidx);
+        if (hwkey_event.event_type == KEY_PRESSED) {
+          input_event(vh->idev, EV_KEY, hwkey_event.keycode, true);
+        }
+        else if (hwkey_event.event_type == KEY_RELEASED) {
+          input_event(vh->idev, EV_KEY, hwkey_event.keycode, false);
+        }
+        else {
+          printk(KERN_ERR "Unknown event type\n");
+          return;
+        }
+
+        input_sync(vh->idev);
+        memset(&vh->vbuf[vqidx], 0x00, sizeof(hwkey_event));
+        vqidx++;
+        if (vqidx == MAX_BUF_COUNT) {
+            vqidx = 0;
+        }
+    }
+
+    virtqueue_kick(vh->vq);
+}
+
+static int virtio_hwkey_open(struct inode *inode, struct file *file)
+{
+    printk(KERN_INFO "virtio hwkey device is opened\n");
+    return 0;
+}
+
+static int virtio_hwkey_release(struct inode *inode, struct file *file)
+{
+    printk(KERN_INFO "virtio hwkey device is closed\n");
+    return 0;
+}
+
+static int input_hwkey_open(struct input_dev *dev)
+{
+    printk(KERN_INFO "input hwkey device is opened\n");
+    return 0;
+}
+
+static void input_hwkey_close(struct input_dev *dev)
+{
+    printk(KERN_INFO "input hwkey device is closed\n");
+}
+
+struct file_operations virtio_hwkey_fops = {
+    .owner   = THIS_MODULE,
+    .open    = virtio_hwkey_open,
+    .release = virtio_hwkey_release,
+};
+
+static int virtio_hwkey_probe(struct virtio_device *vdev)
+{
+    int ret = 0;
+    vqidx = 0;
+
+    printk(KERN_INFO "virtio hwkey driver is probed\n");
+
+    /* init virtio */
+    vdev->priv = vh = kmalloc(sizeof(*vh), GFP_KERNEL);
+    if (!vh) {
+        return -ENOMEM;
+    }
+    memset(&vh->vbuf, 0x00, sizeof(vh->vbuf));
+
+    vh->vdev = vdev;
+
+    vh->vq = virtio_find_single_vq(vh->vdev, vq_hwkey_callback, "virtio-hwkey-vq");
+    if (IS_ERR(vh->vq)) {
+        ret = PTR_ERR(vh->vq);
+
+        kfree(vh);
+        vdev->priv = NULL;
+        return ret;
+    }
+
+    /* enable callback */
+    virtqueue_enable_cb(vh->vq);
+
+    sg_init_table(vh->sg, MAX_BUF_COUNT);
+
+    /* prepare the buffers */
+    for (index = 0; index < MAX_BUF_COUNT; index++) {
+        sg_set_buf(&vh->sg[index], &vh->vbuf[index], sizeof(EmulHwkeyEvent));
+
+        if (err < 0) {
+            printk(KERN_ERR "failed to add buffer\n");
+
+            kfree(vh);
+            vdev->priv = NULL;
+            return ret;
+        }
+    }
+
+    err = virtqueue_add_buf(vh->vq, vh->sg, 0,
+            MAX_BUF_COUNT, (void *)MAX_BUF_COUNT, GFP_ATOMIC);
+
+    /* register for input device */
+    vh->idev = input_allocate_device();
+    if (!vh->idev) {
+        printk(KERN_ERR "failed to allocate a input hwkey device\n");
+        ret = -1;
+
+        kfree(vh);
+        vdev->priv = NULL;
+        return ret;
+    }
+
+    vh->idev->name = "Maru Virtio Hwkey";
+    vh->idev->dev.parent = &(vdev->dev);
+
+    input_set_drvdata(vh->idev, vh);
+    vh->idev->open = input_hwkey_open;
+    vh->idev->close = input_hwkey_close;
+
+    vh->idev->evbit[0] = BIT_MASK(EV_KEY);
+    /* to support any keycode */
+    memset(vh->idev->keybit, 0xffffffff, sizeof(unsigned long) * BITS_TO_LONGS(KEY_CNT));
+
+    ret = input_register_device(vh->idev);
+    if (ret) {
+        printk(KERN_ERR "input hwkey driver cannot registered\n");
+        ret = -1;
+
+        input_free_device(vh->idev);
+        kfree(vh);
+        vdev->priv = NULL;
+        return ret;
+    }
+
+    virtqueue_kick(vh->vq);
+    index = 0;
+
+    return 0;
+}
+
+static void virtio_hwkey_remove(struct virtio_device *vdev)
+{
+    virtio_hwkey *vhk = NULL;
+
+    printk(KERN_INFO "virtio hwkey driver is removed\n");
+
+    vhk = vdev->priv;
+
+    vdev->config->reset(vdev); /* reset device */
+    vdev->config->del_vqs(vdev); /* clean up the queues */
+
+    input_unregister_device(vhk->idev);
+
+    kfree(vhk);
+}
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+static struct virtio_driver virtio_hwkey_driver = {
+    .driver.name = KBUILD_MODNAME,
+    .driver.owner = THIS_MODULE,
+    .id_table = id_table,
+    .probe = virtio_hwkey_probe,
+    .remove = virtio_hwkey_remove,
+};
+
+static int __init virtio_hwkey_init(void)
+{
+    printk(KERN_INFO "virtio hwkey device is initialized\n");
+    return register_virtio_driver(&virtio_hwkey_driver);
+}
+
+static void __exit virtio_hwkey_exit(void)
+{
+    printk(KERN_INFO "virtio hwkey device is destroyed\n");
+    unregister_virtio_driver(&virtio_hwkey_driver);
+}
+
+module_init(virtio_hwkey_init);
+module_exit(virtio_hwkey_exit);
+