virtio: introduce maru_virtio_device
authorSeokYeon Hwang <syeon.hwang@samsung.com>
Wed, 22 Jun 2016 06:17:32 +0000 (15:17 +0900)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Tue, 28 Jun 2016 02:03:24 +0000 (11:03 +0900)
"maru_virtuo_device" structure and new header include convenient API
for using virtqueue and allocating buffer.
Rewrite hwkey device.

Change-Id: Ic3f4d25ba0cf6616f4f9ded86017378ccc0b8b3a
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
(cherry picked from commit ee8604f9a69db762f0618851352e3979010ed181)

drivers/maru/maru_virtio_device.h [new file with mode: 0644]
drivers/maru/maru_virtio_hwkey.c
drivers/maru/maru_virtio_keyboard.c
drivers/maru/maru_virtio_touchscreen.c

diff --git a/drivers/maru/maru_virtio_device.h b/drivers/maru/maru_virtio_device.h
new file mode 100644 (file)
index 0000000..42eb148
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Maru Virtio Input Device Driver
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *  SeokYeon Hwang <syeon.hwang@samsung.com>
+ *  GiWoong Kim <giwoong.kim@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
+ *
+ */
+
+#ifndef _MARU_VIRTIO_H
+#define _MARU_VIRTIO_H
+
+#define MAX_BUF_COUNT 64
+
+struct maru_virtio_device {
+       struct virtio_device *vdev;
+       struct virtqueue *vq;
+       struct scatterlist sg[1];
+
+       spinlock_t lock;
+};
+
+// should be called in the lock
+static inline int add_new_buf(struct maru_virtio_device *mdev,
+        void *buf, unsigned int buf_size)
+{
+    int err = 0;
+
+    sg_init_one(mdev->sg, buf, buf_size);
+
+    err = virtqueue_add_inbuf(mdev->vq, mdev->sg,
+            1, buf, GFP_ATOMIC);
+    if (err < 0) {
+        return err;
+       }
+
+       return 0;
+}
+
+static inline int init_virtio_device(struct virtio_device *vdev,
+        struct maru_virtio_device *mdev, vq_callback_t *c,
+        void *buf, unsigned int buf_size)
+{
+       int index;
+       int err = 0;
+       unsigned long flags;
+
+       spin_lock_init(&mdev->lock);
+
+       mdev->vdev = vdev;
+
+       mdev->vq = virtio_find_single_vq(mdev->vdev, c, "virtio-hwkey-vq");
+       if (IS_ERR(mdev->vq)) {
+               printk(KERN_ERR "failed to find virtqueue\n");
+               return PTR_ERR(mdev->vq);
+       }
+
+       spin_lock_irqsave(&mdev->lock, flags);
+       /* prepare the buffers */
+       for (index = 0; index < MAX_BUF_COUNT; index++) {
+               err = add_new_buf(mdev, buf + (index * buf_size), buf_size);
+               if (err < 0) {
+                       spin_unlock_irqrestore(&mdev->lock, flags);
+                       return err;
+               }
+       }
+       spin_unlock_irqrestore(&mdev->lock, flags);
+
+       virtqueue_kick(mdev->vq);
+
+    return 0;
+}
+
+static inline void deinit_virtio_device(struct virtio_device *vdev) {
+       vdev->config->reset(vdev);
+       vdev->config->del_vqs(vdev);
+}
+
+#endif //_MARU_VIRTIO_H
index 03f30eb21bd125e244a72d9a3fff4d8eafcbbfa2..3dd36051c6cc07614f02d51c7f4e53a8e710b425 100644 (file)
@@ -4,9 +4,8 @@
  * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Contact:
+ *  SeokYeon Hwang <syeon.hwang@samsung.com>
  *  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
 #include <linux/virtio_config.h>
 #include <linux/kthread.h>
 
+#include "maru_virtio_device.h"
+
 MODULE_LICENSE("GPL2");
-MODULE_AUTHOR("Sungmin Ha <sungmin82.ha@samsung.com>");
+MODULE_AUTHOR("SeokYeon Hwangm <syeon.hwang@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 {
+struct hwkey_event {
        uint8_t event_type;
        uint32_t keycode;
-} EmulHwkeyEvent;
+};
 
-typedef struct virtio_hwkey
+struct virtio_hwkey
 {
-       struct virtio_device *vdev;
-       struct virtqueue *vq;
-       struct input_dev *idev;
+       struct maru_virtio_device *mdev;
 
-       struct scatterlist sg[MAX_BUF_COUNT];
-       struct EmulHwkeyEvent vbuf[MAX_BUF_COUNT];
-
-       struct mutex event_mutex;
-} virtio_hwkey;
-
-virtio_hwkey *vh;
+       struct input_dev *idev;
+       struct hwkey_event evtbuf[MAX_BUF_COUNT];
+};
 
 static struct virtio_device_id id_table[] = {
        { VIRTIO_ID_HWKEY, VIRTIO_DEV_ANY_ID },
@@ -78,62 +71,47 @@ enum {
        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;
-       unsigned int len = 0;
-       void *token = NULL;
-#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_INFO "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);
+       unsigned int len; /* not used */
+       struct virtio_hwkey *vh = vq->vdev->priv;
+       struct maru_virtio_device *mdev = vh->mdev;
+       struct hwkey_event *event;
+
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&mdev->lock, flags);
+       while ((event = virtqueue_get_buf(mdev->vq, &len)) != NULL) {
+               spin_unlock_irqrestore(&mdev->lock, flags);
+
+               printk(KERN_INFO "keycode: %d, event_type: %d\n",
+                               event->keycode, event->event_type);
+               if (event->event_type == KEY_PRESSED) {
+                       input_event(vh->idev, EV_KEY, event->keycode, true);
                }
-               else if (hwkey_event.event_type == KEY_RELEASED) {
-                       input_event(vh->idev, EV_KEY, hwkey_event.keycode, false);
+               else if (event->event_type == KEY_RELEASED) {
+                       input_event(vh->idev, EV_KEY, event->keycode, false);
                }
                else {
                        printk(KERN_ERR "Unknown event type\n");
                }
 
                input_sync(vh->idev);
-               memset(&vh->vbuf[vqidx], 0x00, sizeof(hwkey_event));
-               token = virtqueue_get_buf(vh->vq, &len);
-               if (len > 0) {
-                       err = virtqueue_add_inbuf(vh->vq, vh->sg, MAX_BUF_COUNT, token, GFP_ATOMIC);
-               }
 
-               vqidx++;
-               if (vqidx == MAX_BUF_COUNT) {
-                       vqidx = 0;
+               // add new buffer
+               spin_lock_irqsave(&mdev->lock, flags);
+               err = add_new_buf(mdev, event, sizeof(*event));
+               if (err < 0) {
+                       printk(KERN_ERR "failed to add buffer\n");
                }
        }
 
-       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;
+       virtqueue_kick(mdev->vq);
+       spin_unlock_irqrestore(&mdev->lock, flags);
 }
 
 static int input_hwkey_open(struct input_dev *dev)
@@ -147,67 +125,28 @@ 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");
+       struct virtio_hwkey *vh;
 
        /* init virtio */
-       vdev->priv = vh = kmalloc(sizeof(*vh), GFP_KERNEL);
+       vdev->priv = vh = kzalloc(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;
-               }
+       vh->mdev = kzalloc(sizeof(*vh->mdev), GFP_KERNEL);
+       if (!vh->mdev) {
+               ret = -ENOMEM;
+               goto err3;
        }
 
-       err = virtqueue_add_inbuf(vh->vq, vh->sg,
-                       MAX_BUF_COUNT, (void *)vh->vbuf, 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;
+               ret = -ENOMEM;
+               goto err2;
        }
 
        vh->idev->name = "Maru Virtio Hwkey";
@@ -219,39 +158,46 @@ static int virtio_hwkey_probe(struct virtio_device *vdev)
 
        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));
+       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;
+               goto err;
+       }
 
-               input_free_device(vh->idev);
-               kfree(vh);
-               vdev->priv = NULL;
-               return ret;
+       ret = init_virtio_device(vdev, vh->mdev, vq_hwkey_callback,
+                       vh->evtbuf, sizeof(struct hwkey_event));
+       if (ret) {
+               goto err;
        }
 
-       virtqueue_kick(vh->vq);
-       index = 0;
+       printk(KERN_INFO "virtio hwkey driver is probed\n");
 
        return 0;
+
+err:
+       input_free_device(vh->idev);
+err2:
+       kfree(vh->mdev);
+err3:
+       kfree(vh);
+       vdev->priv = NULL;
+       return ret;
 }
 
 static void virtio_hwkey_remove(struct virtio_device *vdev)
 {
-       virtio_hwkey *vhk = NULL;
-
-       printk(KERN_INFO "virtio hwkey driver is removed\n");
+       struct virtio_hwkey *vh = vdev->priv;
 
-       vhk = vdev->priv;
+       input_unregister_device(vh->idev);
+       deinit_virtio_device(vdev);
 
-       vdev->config->reset(vdev); /* reset device */
-       vdev->config->del_vqs(vdev); /* clean up the queues */
+       kfree(vh);
 
-       input_unregister_device(vhk->idev);
-
-       kfree(vhk);
+       printk(KERN_INFO "virtio hwkey driver is removed\n");
 }
 
 MODULE_DEVICE_TABLE(virtio, id_table);
@@ -278,4 +224,3 @@ static void __exit virtio_hwkey_exit(void)
 
 module_init(virtio_hwkey_init);
 module_exit(virtio_hwkey_exit);
-
index a358493b128f2e5a58e5ea455569d354356a5af3..66db8fc0b8b6d4deeb7c51795263ceb797f19322 100644 (file)
@@ -4,8 +4,8 @@
  * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Contact:
- *  GiWoong Kim <giwoong.kim@samsung.com>
  *  SeokYeon Hwang <syeon.hwang@samsung.com>
+ *  GiWoong Kim <giwoong.kim@samsung.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -38,6 +38,7 @@
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
 
+#include "maru_virtio_device.h"
 
 MODULE_LICENSE("GPL2");
 MODULE_AUTHOR("SeokYeon Hwangm <syeon.hwang@samsung.com>");
@@ -49,11 +50,9 @@ MODULE_DESCRIPTION("Emulator virtio keyboard driver");
 #define VKBD_LOG(log_level, fmt, ...) \
        printk(log_level "%s: " fmt, DRIVER_NAME, ##__VA_ARGS__)
 
-#define MAX_BUF_COUNT 100
-
 //#define DEBUG
 
-struct EmulKbdEvent
+struct keyboard_event
 {
        uint16_t code;
        uint16_t value;
@@ -61,14 +60,10 @@ struct EmulKbdEvent
 
 struct virtio_keyboard
 {
-       struct virtio_device *vdev;
-       struct virtqueue *vq;
-       struct input_dev *idev;
+       struct maru_virtio_device *mdev;
 
-       struct scatterlist sg[1];
-       struct EmulKbdEvent evtbuf[MAX_BUF_COUNT];
-
-       spinlock_t lock;
+       struct input_dev *idev;
+       struct keyboard_event evtbuf[MAX_BUF_COUNT];
 };
 
 static struct virtio_device_id id_table[] = {
@@ -76,38 +71,37 @@ static struct virtio_device_id id_table[] = {
        { 0 },
 };
 
-static void vq_keyboard_handle(struct virtqueue *vq)
+static void vq_keyboard_callback(struct virtqueue *vq)
 {
        unsigned int len; /* not used */
        struct virtio_keyboard *vkbd = vq->vdev->priv;
-       struct EmulKbdEvent *event;
+       struct maru_virtio_device *mdev = vkbd->mdev;
+       struct keyboard_event *event;
 
        unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&vkbd->lock, flags);
-       while ((event = virtqueue_get_buf(vkbd->vq, &len)) != NULL) {
-               spin_unlock_irqrestore(&vkbd->lock, flags);
+       spin_lock_irqsave(&mdev->lock, flags);
+       while ((event = virtqueue_get_buf(mdev->vq, &len)) != NULL) {
+               spin_unlock_irqrestore(&mdev->lock, flags);
 #ifdef DEBUG
         printk(KERN_ERR "keyboard code = %d, value = %d\n", event->code,
                 event->value);
 #endif
+
                input_event(vkbd->idev, EV_KEY, event->code, event->value);
                input_sync(vkbd->idev);
 
                // add new buffer
-               spin_lock_irqsave(&vkbd->lock, flags);
-               sg_init_one(vkbd->sg, event, sizeof(*event));
-               err = virtqueue_add_inbuf(vkbd->vq, vkbd->sg,
-                               1, event, GFP_ATOMIC);
-
+               spin_lock_irqsave(&mdev->lock, flags);
+               err = add_new_buf(mdev, event, sizeof(*event));
                if (err < 0) {
-                       printk(KERN_ERR "failed to add buffer!\n");
+                       printk(KERN_ERR "failed to add buffer\n");
                }
        }
 
-       virtqueue_kick(vkbd->vq);
-       spin_unlock_irqrestore(&vkbd->lock, flags);
+       virtqueue_kick(mdev->vq);
+       spin_unlock_irqrestore(&mdev->lock, flags);
 }
 
 static int input_keyboard_open(struct input_dev *dev)
@@ -124,9 +118,6 @@ static void input_keyboard_close(struct input_dev *dev)
 static int virtio_keyboard_probe(struct virtio_device *vdev)
 {
        int ret = 0;
-       int index = 0;
-       int err = 0;
-       unsigned long flags;
        struct virtio_keyboard *vkbd;
 
        VKBD_LOG(KERN_INFO, "driver is probed\n");
@@ -135,24 +126,18 @@ static int virtio_keyboard_probe(struct virtio_device *vdev)
        if (!vkbd) {
                return -ENOMEM;
        }
-
-       vkbd->vdev = vdev;
-
-       vkbd->vq = virtio_find_single_vq(vkbd->vdev, vq_keyboard_handle, "virtio-keyboard-vq");
-       if (IS_ERR(vkbd->vq)) {
-               ret = PTR_ERR(vkbd->vq);
-               kfree(vkbd);
-               vdev->priv = NULL;
-               return ret;
+       vkbd->mdev = kzalloc(sizeof(*vkbd->mdev), GFP_KERNEL);
+       if (!vkbd->mdev) {
+               ret = -ENOMEM;
+               goto err3;
        }
 
        /* register for input device */
        vkbd->idev = input_allocate_device();
        if (!vkbd->idev) {
                VKBD_LOG(KERN_ERR, "failed to allocate a input device.\n");
-               kfree(vkbd);
-               vdev->priv = NULL;
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err2;
        }
 
        vkbd->idev->name = "Maru VirtIO Keyboard";
@@ -184,51 +169,39 @@ static int virtio_keyboard_probe(struct virtio_device *vdev)
        ret = input_register_device(vkbd->idev);
        if (ret) {
                VKBD_LOG(KERN_ERR, "failed to register a input device.\n");
-               input_free_device(vkbd->idev);
-               kfree(vkbd);
-               vdev->priv = NULL;
-               return ret;
+               goto err;
        }
 
-       spin_lock_irqsave(&vkbd->lock, flags);
-       for (index = 0; index < MAX_BUF_COUNT; index++) {
-               sg_init_one(vkbd->sg, &vkbd->evtbuf[index], sizeof(&vkbd->evtbuf[index]));
-
-               err = virtqueue_add_inbuf(vkbd->vq, vkbd->sg,
-                               1, &vkbd->evtbuf[index], GFP_ATOMIC);
-
-               if (err < 0) {
-                       printk(KERN_ERR "failed to add buffer\n");
-
-                       kfree(vkbd);
-                       vdev->priv = NULL;
-                       return err;
-               }
+       ret = init_virtio_device(vdev, vkbd->mdev, vq_keyboard_callback,
+                       vkbd->evtbuf, sizeof(struct keyboard_event));
+       if (ret) {
+               goto err;
        }
-       spin_unlock_irqrestore(&vkbd->lock, flags);
 
-       virtqueue_kick(vkbd->vq);
+       VKBD_LOG(KERN_INFO, "driver is probed\n");
 
        return 0;
+
+err:
+       input_free_device(vkbd->idev);
+err2:
+       kfree(vkbd->mdev);
+err3:
+       kfree(vkbd);
+       vdev->priv = NULL;
+       return ret;
 }
 
 static void virtio_keyboard_remove(struct virtio_device *vdev)
 {
        struct virtio_keyboard *vkbd = vdev->priv;
 
-       VKBD_LOG(KERN_INFO, "driver is removed.\n");
-       if (!vkbd) {
-               VKBD_LOG(KERN_ERR, "vkbd is NULL.\n");
-               return;
-       }
-
-       vdev->config->reset(vdev);
-       vdev->config->del_vqs(vdev);
-
        input_unregister_device(vkbd->idev);
+       deinit_virtio_device(vdev);
 
        kfree(vkbd);
-       vkbd = NULL;
+
+       VKBD_LOG(KERN_INFO, "driver is removed.\n");
 }
 
 MODULE_DEVICE_TABLE(virtio, id_table);
index 5aa04f87e551006d7f6f40d3fd5c973e836601b4..1e5650eb69a4b2437ebbbe8b25e0c4ade83e01b9 100644 (file)
@@ -4,8 +4,8 @@
  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Contact:
- *  GiWoong Kim <giwoong.kim@samsung.com>
  *  SeokYeon Hwang <syeon.hwang@samsung.com>
+ *  GiWoong Kim <giwoong.kim@samsung.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -40,6 +40,7 @@
 #include <linux/virtio_config.h>
 #include <linux/kthread.h>
 
+#include "maru_virtio_device.h"
 
 MODULE_LICENSE("GPL2");
 MODULE_AUTHOR("SeokYeon Hwangm <syeon.hwang@samsung.com>");
@@ -51,8 +52,6 @@ MODULE_DESCRIPTION("Emulator virtio touchscreen driver");
 #define MAX_TRKID 10
 #define ABS_PRESSURE_MAX 255
 
-#define MAX_BUF_COUNT MAX_TRKID
-
 //#define DEBUG
 
 /* This structure must match the qemu definitions */
@@ -64,14 +63,10 @@ struct touch_event
 
 struct virtio_touchscreen
 {
-       struct virtio_device *vdev;
-       struct input_dev *idev;
+       struct maru_virtio_device *mdev;
 
-       struct virtqueue *vq;
-       struct scatterlist sg[1];
+       struct input_dev *idev;
        struct touch_event evtbuf[MAX_BUF_COUNT];
-
-       spinlock_t lock;
 };
 
 static struct virtio_device_id id_table[] = {
@@ -88,14 +83,15 @@ static void vq_touchscreen_callback(struct virtqueue *vq)
        unsigned int len; /* not used */
        unsigned int finger_id; /* finger id */
        struct virtio_touchscreen *vt = vq->vdev->priv;
+       struct maru_virtio_device *mdev = vt->mdev;
        struct touch_event *event;
 
        unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&vt->lock, flags);
-       while ((event = virtqueue_get_buf(vt->vq, &len)) != NULL) {
-               spin_unlock_irqrestore(&vt->lock, flags);
+       spin_lock_irqsave(&mdev->lock, flags);
+       while ((event = virtqueue_get_buf(mdev->vq, &len)) != NULL) {
+               spin_unlock_irqrestore(&mdev->lock, flags);
 #ifdef DEBUG
                printk(KERN_INFO "touchscreen x=%d, y=%d, z=%d, state=%d, len=%d\n",
                                event->x, event->y, event->z, event->state, len);
@@ -125,18 +121,15 @@ static void vq_touchscreen_callback(struct virtqueue *vq)
                }
 
                // add new buffer
-               spin_lock_irqsave(&vt->lock, flags);
-               sg_init_one(vt->sg, event, sizeof(*event));
-               err = virtqueue_add_inbuf(vt->vq, vt->sg,
-                               1, event, GFP_ATOMIC);
-
+               spin_lock_irqsave(&mdev->lock, flags);
+               err = add_new_buf(mdev, event, sizeof(*event));
                if (err < 0) {
-                       printk(KERN_ERR "failed to add buffer!\n");
+                       printk(KERN_ERR "failed to add buffer\n");
                }
        }
 
-       virtqueue_kick(vt->vq);
-       spin_unlock_irqrestore(&vt->lock, flags);
+       virtqueue_kick(mdev->vq);
+       spin_unlock_irqrestore(&mdev->lock, flags);
 }
 
 static int input_touchscreen_open(struct input_dev *dev)
@@ -154,43 +147,13 @@ extern char *saved_command_line;
 
 #define VM_RESOLUTION_KEY "vm_resolution="
 
-static int virtio_touchscreen_probe(struct virtio_device *vdev)
+static void get_resolution(unsigned long *width, unsigned long *height)
 {
-       unsigned long width = 0;
-       unsigned long height = 0;
-       char *cmdline = NULL;
-       char *value = NULL;
-       char *tmp = NULL;
        int err = 0;
-       int ret = 0;
-
-       unsigned long flags;
-       int index;
-       struct virtio_touchscreen *vt;
-
-       printk(KERN_INFO "virtio touchscreen driver is probed\n");
-
-       /* init virtio */
-       vdev->priv = vt = kzalloc(sizeof(*vt), GFP_KERNEL);
-       if (!vt) {
-               return -ENOMEM;
-       }
-
-       spin_lock_init(&vt->lock);
-
-       vt->vdev = vdev;
-
-       vt->vq = virtio_find_single_vq(vt->vdev,
-                       vq_touchscreen_callback, "virtio-touchscreen-vq");
-       if (IS_ERR(vt->vq)) {
-               ret = PTR_ERR(vt->vq);
-
-               kfree(vt);
-               vdev->priv = NULL;
-               return ret;
-       }
+       char *tmp = NULL;
+       char *value = NULL;
+       char *cmdline = kzalloc(strlen(saved_command_line) + 1, GFP_KERNEL);
 
-       cmdline = kzalloc(strlen(saved_command_line) + 1, GFP_KERNEL);
        if (cmdline) {
                /* get VM resolution */
                strcpy(cmdline, saved_command_line);
@@ -200,36 +163,55 @@ static int virtio_touchscreen_probe(struct virtio_device *vdev)
                        tmp += strlen(VM_RESOLUTION_KEY);
 
                        value = strsep(&tmp, "x");
-                       err = kstrtoul(value, 10, &width);
+                       err = kstrtoul(value, 10, width);
                        if (err) {
                                printk(KERN_WARNING "vm width option is not defined\n");
-                               width = 0;
+                               *width = 0;
                        }
 
                        value = strsep(&tmp, " ");
-                       err = kstrtoul(value, 10, &height);
+                       err = kstrtoul(value, 10, height);
                        if (err) {
                                printk(KERN_WARNING "vm height option is not defined\n");
-                               height = 0;
+                               *height = 0;
                        }
                }
 
                kfree(cmdline);
        }
 
-       if (width != 0 && height != 0) {
-               printk(KERN_INFO "emul resolution : %lux%lu\n", width, height);
+       if (*width != 0 && *height != 0) {
+               printk(KERN_INFO "emul resolution : %lux%lu\n", *width, *height);
+       }
+}
+
+static int virtio_touchscreen_probe(struct virtio_device *vdev)
+{
+       unsigned long width = 0;
+       unsigned long height = 0;
+       int ret = 0;
+
+       struct virtio_touchscreen *vt;
+
+       /* init virtio */
+       vdev->priv = vt = kzalloc(sizeof(*vt), GFP_KERNEL);
+       if (!vt) {
+               return -ENOMEM;
        }
+       vt->mdev = kzalloc(sizeof(*vt->mdev), GFP_KERNEL);
+       if (!vt->mdev) {
+               ret = -ENOMEM;
+               goto err3;
+       }
+
+       get_resolution(&width, &height);
 
        /* register for input device */
        vt->idev = input_allocate_device();
        if (!vt->idev) {
                printk(KERN_ERR "failed to allocate a input touchscreen device\n");
-               ret = -1;
-
-               kfree(vt);
-               vdev->priv = NULL;
-               return ret;
+               ret = -ENOMEM;
+               goto err2;
        }
 
        vt->idev->name = "Maru Virtio Touchscreen";
@@ -262,52 +244,40 @@ static int virtio_touchscreen_probe(struct virtio_device *vdev)
        if (ret) {
                printk(KERN_ERR "input touchscreen driver cannot registered\n");
                ret = -1;
-
-               input_mt_destroy_slots(vt->idev);
-               input_free_device(vt->idev);
-               kfree(vt);
-               vdev->priv = NULL;
-               return ret;
+               goto err;
        }
 
-       spin_lock_irqsave(&vt->lock, flags);
-       /* prepare the buffers */
-       for (index = 0; index < MAX_BUF_COUNT; index++) {
-               sg_init_one(vt->sg, &vt->evtbuf[index], sizeof(&vt->evtbuf[index]));
-
-               err = virtqueue_add_inbuf(vt->vq, vt->sg,
-                               1, &vt->evtbuf[index], GFP_ATOMIC);
-
-               if (err < 0) {
-                       printk(KERN_ERR "failed to add buffer\n");
-
-                       kfree(vt);
-                       vdev->priv = NULL;
-                       return err;
-               }
+       ret = init_virtio_device(vdev, vt->mdev, vq_touchscreen_callback,
+                       vt->evtbuf, sizeof(struct touch_event));
+       if (ret) {
+               goto err;
        }
-       spin_unlock_irqrestore(&vt->lock, flags);
 
-       virtqueue_kick(vt->vq);
+       printk(KERN_INFO "virtio touchscreen driver is probed\n");
 
        return 0;
+
+err:
+       input_free_device(vt->idev);
+err2:
+       kfree(vt->mdev);
+err3:
+       kfree(vt);
+       vdev->priv = NULL;
+       return ret;
 }
 
 static void virtio_touchscreen_remove(struct virtio_device *vdev)
 {
-       struct virtio_touchscreen *vt = NULL;
-
-       printk(KERN_INFO "virtio touchscreen driver is removed\n");
-
-       vt = vdev->priv;
-
-       vdev->config->reset(vdev); /* reset device */
-       vdev->config->del_vqs(vdev); /* clean up the queues */
+       struct virtio_touchscreen *vt = vdev->priv;
 
        input_unregister_device(vt->idev);
        input_mt_destroy_slots(vt->idev);
+       deinit_virtio_device(vdev);
 
        kfree(vt);
+
+       printk(KERN_INFO "virtio touchscreen driver is removed\n");
 }
 
 MODULE_DEVICE_TABLE(virtio, id_table);