maru_virtio_keyboard : add virtio-keyboard driver.
authorKitae Kim <kt920.kim@samsung.com>
Fri, 26 Oct 2012 06:45:19 +0000 (15:45 +0900)
committerKitae Kim <kt920.kim@samsung.com>
Fri, 26 Oct 2012 06:48:05 +0000 (15:48 +0900)
Implement a driver for virtio-keyboard device.
In addition to this, enable CONFIG_HOTPLUG_PCI_ACPI to support pci hotplug feature.

Signed-off-by : Kitae Kim <kt920.kim@samsung.com>

arch/x86/configs/i386_emul_defconfig
drivers/maru/Kconfig
drivers/maru/Makefile
drivers/maru/maru_virtio_keyboard.c [new file with mode: 0644]
include/linux/virtio_ids.h

index 33a326c8df2d33be3cec602d4b72b82a359a47a0..c81834e9bedb9f0db6ac1baebc491533cb7dff2b 100644 (file)
@@ -481,7 +481,7 @@ CONFIG_ACPI_THERMAL=y
 # CONFIG_ACPI_CUSTOM_DSDT is not set
 CONFIG_ACPI_BLACKLIST_YEAR=0
 # CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_PCI_SLOT is not set
+CONFIG_ACPI_PCI_SLOT=y
 CONFIG_X86_PM_TIMER=y
 CONFIG_ACPI_CONTAINER=y
 # CONFIG_ACPI_SBS is not set
@@ -596,7 +596,8 @@ CONFIG_PCCARD_NONSTATIC=y
 CONFIG_HOTPLUG_PCI=y
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 # CONFIG_HOTPLUG_PCI_COMPAQ is not set
-# CONFIG_HOTPLUG_PCI_ACPI is not set
+CONFIG_HOTPLUG_PCI_ACPI=y
+# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
 # CONFIG_HOTPLUG_PCI_CPCI is not set
 # CONFIG_HOTPLUG_PCI_SHPC is not set
 # CONFIG_RAPIDIO is not set
@@ -2775,6 +2776,7 @@ CONFIG_MARU_JACK=y
 CONFIG_MARU_POWER_SUPPLY=y
 CONFIG_MARU_USB_MASS_STORAGE=y
 CONFIG_MARU_USB_MODE=y
+CONFIG_MARU_VIRTIO_KEYBOARD=y
 
 #
 # Firmware Drivers
index 8313e4e23f2404daa53510d96b7902b85127d2c4..c51aa27c57d4a01e5cfc071f9032e5be151562a2 100644 (file)
@@ -55,3 +55,7 @@ config MARU_USB_MASS_STORAGE
 config MARU_USB_MODE
        tristate "MARU Usb mode Driver"
        depends on MARU != n
+
+config MARU_VIRTIO_KEYBOARD
+       tristate "MARU VirtIO Keyboard Driver"
+       depends on MARU != n
index 5659e94e060b71dde3c6c87ec1c3e9b54397c89a..8ae7d3c1d328dde83fc3fd9186dd2e2bbe484e9a 100644 (file)
@@ -10,3 +10,4 @@ obj-$(CONFIG_MARU_JACK) += maru_jack.o
 obj-$(CONFIG_MARU_POWER_SUPPLY) += maru_power_supply.o
 obj-$(CONFIG_MARU_USB_MASS_STORAGE) += maru_usb_mass_storage.o
 obj-$(CONFIG_MARU_USB_MODE) += maru_usb_mode.o
+obj-$(CONFIG_MARU_VIRTIO_KEYBOARD) += maru_virtio_keyboard.o
diff --git a/drivers/maru/maru_virtio_keyboard.c b/drivers/maru/maru_virtio_keyboard.c
new file mode 100644 (file)
index 0000000..c7fc651
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Maru Virtio Keyboard Device Driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ *  Kitae Kim <kitae.kim@samsung.com>
+ *  SeokYeon Hwang <syeon.hwang@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>
+
+MODULE_LICENSE("GPL2");
+MODULE_AUTHOR("Kitae Kim <kt920.kim@samsung.com>");
+MODULE_DESCRIPTION("Emulator Virtio Keyboard driver");
+
+#define DEVICE_NAME "virtio-keyboard"
+
+struct EmulKbdEvent
+{
+       uint16_t code;
+       uint16_t value;
+};
+
+struct virtio_keyboard
+{
+    struct virtio_device *vdev;
+    struct virtqueue *vq;
+    struct input_dev *idev;
+
+       struct EmulKbdEvent kbdevt;
+       struct scatterlist sg[2];
+};
+
+struct virtio_keyboard *vkbd;
+
+
+static struct virtio_device_id id_table[] = {
+    { VIRTIO_ID_KEYBOARD, VIRTIO_DEV_ANY_ID },
+    { 0 },
+};
+
+static void vq_keyboard_handle(struct virtqueue *vq)
+{
+       int err = 0;
+       int len = 0;
+       void *data;
+
+    printk(KERN_INFO "virtio-keyboard: virtqueue callback\n");
+
+       data = virtqueue_get_buf(vq, &len);
+       if (!data) {
+           printk(KERN_INFO "virtio-keyboard: there is no used buffer.\n");
+               return;
+       }
+
+       printk(KERN_INFO "virtio-keyboard: keyboard event code: %d, value:%d\n",
+                       vkbd->kbdevt.code, vkbd->kbdevt.value);
+
+       /* how to get keycode and value. */
+       input_event(vkbd->idev, EV_KEY, vkbd->kbdevt.code, vkbd->kbdevt.value);
+       input_sync(vkbd->idev);
+
+       // TODO : need to improve codes which are about to buffer transfer.
+       err = virtqueue_add_buf (vq, vkbd->sg, 0, 1, (void *)1, GFP_ATOMIC);
+       if (err < 0) {
+               printk(KERN_ERR "virtio-keyboard: failed to add buffer to virtqueue.\n");
+               return;
+       }
+
+#if 0
+       err = virtqueue_add_buf (vq, &kbd->sg, 0, 1, (void *)1, GFP_ATOMIC);
+       if (err < 0) {
+               printk(KERN_ERR "virtio-keyboard: failed to add buffer to virtqueue.\n");
+               return;
+       }
+
+       virtqueue_kick(kbd->vq);
+
+       while (!virtqueue_get_buf(kbd->vq, &len))
+               cpu_relax();
+#endif
+
+}
+
+static int virtio_keyboard_open(struct inode *inode, struct file *file)
+{
+    printk(KERN_INFO "virtio-keyboard: opened\n");
+    return 0;
+}
+
+static int virtio_keyboard_release(struct inode *inode, struct file *file)
+{
+    printk(KERN_INFO "virtio-keyboard: closed\n");
+    return 0;
+}
+
+static int input_keyboard_open(struct input_dev *dev)
+{
+    printk(KERN_INFO "virtio-keyboard: input_keyboard_open\n");
+    return 0;
+}
+
+static void input_keyboard_close(struct input_dev *dev)
+{
+    printk(KERN_INFO "virtio-keyboard: input_keyboard_close\n");
+}
+
+struct file_operations virtio_keyboard_fops = {
+    .owner   = THIS_MODULE,
+    .open    = virtio_keyboard_open,
+    .release = virtio_keyboard_release,
+};
+
+static int virtio_keyboard_probe(struct virtio_device *vdev)
+{
+    int ret = 0;
+
+    printk(KERN_INFO "virtio-keyboard: driver is probed\n");
+
+    vdev->priv = vkbd = kmalloc(sizeof(struct virtio_keyboard), GFP_KERNEL);
+    if (!vkbd) {
+        return -ENOMEM;
+    }
+
+    vkbd->vdev = vdev;
+
+       /* determine whether callback func needs or not */
+    vkbd->vq = virtio_find_single_vq(vkbd->vdev, vq_keyboard_handle, "virtio-keyboard-vq");
+    if (IS_ERR(vkbd->vq)) {
+        ret = PTR_ERR(vkbd->vq);
+        goto error1;
+    }
+
+    /* register for input device */
+    vkbd->idev = input_allocate_device();
+    if (!vkbd->idev) {
+        printk(KERN_ERR "virtio-keyboard: failed to allocate a input device.\n");
+        ret = -1;
+        goto error1;
+    }
+
+    vkbd->idev->name = "Maru VirtIO Keyboard";
+    vkbd->idev->dev.parent = &(vdev->dev);
+
+    input_set_drvdata(vkbd->idev, vkbd);
+    vkbd->idev->open = input_keyboard_open;
+    vkbd->idev->close = input_keyboard_close;
+
+       /* initialize a device as a keyboard device.
+        * refer to struct input_dev from input.h.  */
+       vkbd->idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP)
+                               | BIT_MASK(EV_MSC) | BIT_MASK(EV_LED);
+       vkbd->idev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL)
+                               | BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE)
+                               | BIT_MASK(LED_KANA);
+       set_bit(MSC_SCAN, vkbd->idev->mscbit);
+
+       // TODO : need to change keybit field. not to input fixed value.
+       vkbd->idev->keybit[0] = 0xfffffffe;
+       vkbd->idev->keybit[1] = 0xffffffff;
+       vkbd->idev->keybit[2] = 0xffefffff;
+       vkbd->idev->keybit[3] = 0xfebeffdf;
+       vkbd->idev->keybit[4] = 0xc14057ff;
+       vkbd->idev->keybit[5] = 0xff9f207a;
+       vkbd->idev->keybit[6] = 0x7;
+       vkbd->idev->keybit[7] = 0x10000;
+
+    ret = input_register_device(vkbd->idev);
+    if (ret) {
+        printk(KERN_ERR "virtio-keyboard: failed to register a input device.\n");
+        ret = -1;
+        goto error2;
+    }
+
+#if 1 
+       sg_init_table(vkbd->sg, 2);
+       sg_set_buf(vkbd->sg, &vkbd->kbdevt, sizeof(struct EmulKbdEvent) * 2);
+#endif
+
+       ret = virtqueue_add_buf(vkbd->vq, &vkbd->sg, 0, 1, (void *)1, GFP_ATOMIC);
+       if (ret < 0) {
+               printk(KERN_ERR "virtio-keyboard: failed to add buffer to virtqueue.\n");
+               goto error3;
+       }
+
+       virtqueue_kick(vkbd->vq);
+
+    return 0;
+
+error3:
+    input_unregister_device(vkbd->idev);
+error2:
+    input_free_device(vkbd->idev);
+error1:
+    kfree(vkbd);
+    vdev->priv = NULL;
+
+    return ret;
+}
+
+static void __devexit virtio_keyboard_remove(struct virtio_device *vdev)
+{
+       struct virtio_keyboard *vkbd = vdev->priv;
+
+    printk(KERN_INFO "virtio-keyboard: driver is removed.\n");
+
+    vdev->config->reset(vdev);
+    vdev->config->del_vqs(vdev);
+
+    input_unregister_device(vkbd->idev);
+    input_free_device(vkbd->idev);
+}
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+static struct virtio_driver virtio_keyboard_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .owner = THIS_MODULE,
+       },
+    .id_table = id_table,
+    .probe = virtio_keyboard_probe,
+    .remove = virtio_keyboard_remove,
+#if 0
+#ifdef CONFIG_PM
+    .freeze = virtio_codec_freeze, 
+    .restore = virtio_codec_restore,
+#endif
+#endif
+};
+
+static int __init virtio_keyboard_init(void)
+{
+    printk(KERN_INFO "virtio-keyboard: driver is initialized.\n");
+    return register_virtio_driver(&virtio_keyboard_driver);
+}
+
+static void __exit virtio_keyboard_exit(void)
+{
+    printk(KERN_INFO "virtio-keyboard: driver is destroyed.\n");
+    unregister_virtio_driver(&virtio_keyboard_driver);
+}
+
+module_init(virtio_keyboard_init);
+module_exit(virtio_keyboard_exit);
index 64858993c09f354fc6227774811828e01446355a..7c0f211056894607ce783b43fa8ffdbd84519334 100644 (file)
@@ -41,7 +41,8 @@
 
 #ifdef CONFIG_MARU
 /* Maru devices */
-#define VIRTIO_ID_TOUCHSCREEN 11 /* virtio touchscreen */
+#define VIRTIO_ID_TOUCHSCREEN  11 /* virtio touchscreen */
+#define VIRTIO_ID_KEYBOARD     12 /* virtio keyboard */
 #endif
 
 #endif /* _LINUX_VIRTIO_IDS_H */