From: GiWoong Kim Date: Thu, 9 Jan 2014 03:14:24 +0000 (+0900) Subject: hwkey: added Maru virtio hwkey driver X-Git-Tag: submit/tizen_common/20140905.094502~117^2~99 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2d13f408e85cf4c859038f00b9de1e4818e6c3e6;p=sdk%2Femulator%2Femulator-kernel.git hwkey: added Maru virtio hwkey driver Change-Id: I90f8409eb62c2b52f9c9787f88d3df450ca4db45 Signed-off-by: GiWoong Kim --- diff --git a/arch/x86/configs/i386_tizen_emul_defconfig b/arch/x86/configs/i386_tizen_emul_defconfig index 079027e..da89e93 100644 --- a/arch/x86/configs/i386_tizen_emul_defconfig +++ b/arch/x86/configs/i386_tizen_emul_defconfig @@ -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 diff --git a/drivers/maru/Kconfig b/drivers/maru/Kconfig index 528cd38f..f8adb6a 100644 --- a/drivers/maru/Kconfig +++ b/drivers/maru/Kconfig @@ -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 + diff --git a/drivers/maru/Makefile b/drivers/maru/Makefile index 5d4bc40..ef9bc6c 100644 --- a/drivers/maru/Makefile +++ b/drivers/maru/Makefile @@ -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 index 0000000..c9f1ffb --- /dev/null +++ b/drivers/maru/maru_virtio_hwkey.c @@ -0,0 +1,275 @@ +/* + * Maru Virtio Hwkey Device Driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Sungmin Ha + * Sangjin Kim + * YeongKyoon Lee + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL2"); +MODULE_AUTHOR("Sungmin Ha "); +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); +