input: rewrite virtio touchscreen / keyboard device
authorSeokYeon Hwang <syeon.hwang@samsung.com>
Wed, 15 Jun 2016 08:35:10 +0000 (17:35 +0900)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Thu, 16 Jun 2016 05:33:53 +0000 (14:33 +0900)
Simplified input processing logics.
Used proper virtio APIs.

Change-Id: I24a8564842fbb0d3833c4c2bf21e658c85c00cb0
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
drivers/maru/maru_virtio_keyboard.c
drivers/maru/maru_virtio_touchscreen.c

index f318ef153a84329bfd1d59928b2f4a874f8cf5df..a358493b128f2e5a58e5ea455569d354356a5af3 100644 (file)
@@ -4,9 +4,8 @@
  * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Contact:
- *  Kitae Kim <kitae.kim@samsung.com>
+ *  GiWoong Kim <giwoong.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
 #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");
+MODULE_AUTHOR("SeokYeon Hwangm <syeon.hwang@samsung.com>");
+MODULE_DESCRIPTION("Emulator virtio keyboard driver");
+
 
 #define DRIVER_NAME "virtio-keyboard"
+
 #define VKBD_LOG(log_level, fmt, ...) \
        printk(log_level "%s: " fmt, DRIVER_NAME, ##__VA_ARGS__)
 
-#define KBD_BUF_SIZE 100
-static int vqidx = 0;
+#define MAX_BUF_COUNT 100
+
+//#define DEBUG
 
 struct EmulKbdEvent
 {
@@ -62,14 +65,12 @@ struct virtio_keyboard
        struct virtqueue *vq;
        struct input_dev *idev;
 
-       struct EmulKbdEvent kbdevt[KBD_BUF_SIZE];
-       struct scatterlist sg[KBD_BUF_SIZE];
+       struct scatterlist sg[1];
+       struct EmulKbdEvent evtbuf[MAX_BUF_COUNT];
 
-       struct mutex event_mutex;
+       spinlock_t lock;
 };
 
-struct virtio_keyboard *vkbd;
-
 static struct virtio_device_id id_table[] = {
        { VIRTIO_ID_KEYBOARD, VIRTIO_DEV_ANY_ID },
        { 0 },
@@ -77,42 +78,36 @@ static struct virtio_device_id id_table[] = {
 
 static void vq_keyboard_handle(struct virtqueue *vq)
 {
-       int err = 0, len = 0;
-       void *data;
-       struct EmulKbdEvent kbdevent;
-
-       VKBD_LOG(KERN_DEBUG, "virtqueue callback.\n");
-       data = virtqueue_get_buf(vq, &len);
-       if (!data) {
-               VKBD_LOG(KERN_ERR, "there is no available buffer.\n");
-               return;
-       }
-
-       VKBD_LOG(KERN_DEBUG, "vqidx: %d\n", vqidx);
-       while (1) {
-               memcpy(&kbdevent, &vkbd->kbdevt[vqidx], sizeof(kbdevent));
-#if 1
-               if (kbdevent.code == 0) {
-                       break;
-               }
+       unsigned int len; /* not used */
+       struct virtio_keyboard *vkbd = vq->vdev->priv;
+       struct EmulKbdEvent *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);
+#ifdef DEBUG
+        printk(KERN_ERR "keyboard code = %d, value = %d\n", event->code,
+                event->value);
 #endif
-               /* how to get keycode and value. */
-               input_event(vkbd->idev, EV_KEY, kbdevent.code, kbdevent.value);
+               input_event(vkbd->idev, EV_KEY, event->code, event->value);
                input_sync(vkbd->idev);
-               printk(KERN_ERR "input_event code = %d, value = %d\n", kbdevent.code, kbdevent.value);
-               memset(&vkbd->kbdevt[vqidx], 0x00, sizeof(kbdevent));
-               vqidx++;
-               if (vqidx == KBD_BUF_SIZE) {
-                       vqidx = 0;
+
+               // 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);
+
+               if (err < 0) {
+                       printk(KERN_ERR "failed to add buffer!\n");
                }
        }
-       err = virtqueue_add_inbuf(vq, vkbd->sg, KBD_BUF_SIZE, (void *)vkbd->kbdevt, GFP_ATOMIC);
-       if (err < 0) {
-               VKBD_LOG(KERN_ERR, "failed to add buffer to virtqueue.\n");
-               return;
-       }
 
        virtqueue_kick(vkbd->vq);
+       spin_unlock_irqrestore(&vkbd->lock, flags);
 }
 
 static int input_keyboard_open(struct input_dev *dev)
@@ -126,42 +121,22 @@ static void input_keyboard_close(struct input_dev *dev)
        VKBD_LOG(KERN_DEBUG, "input_keyboard_close\n");
 }
 
-#if 0
-static int virtio_keyboard_open(struct inode *inode, struct file *file)
-{
-       VKBD_LOG(KERN_DEBUG, "opened.\n");
-       return 0;
-}
-
-static int virtio_keyboard_release(struct inode *inode, struct file *file)
-{
-       VKBD_LOG(KERN_DEBUG, "closed\n");
-       return 0;
-}
-
-struct file_operations virtio_keyboard_fops = {
-       .owner   = THIS_MODULE,
-       .open   = virtio_keyboard_open,
-       .release = virtio_keyboard_release,
-};
-#endif
-
 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");
-       vqidx = 0;
 
-       vdev->priv = vkbd = kmalloc(sizeof(struct virtio_keyboard), GFP_KERNEL);
+       vdev->priv = vkbd = kzalloc(sizeof(struct virtio_keyboard), GFP_KERNEL);
        if (!vkbd) {
                return -ENOMEM;
        }
-       memset(&vkbd->kbdevt, 0x00, sizeof(vkbd->kbdevt));
 
        vkbd->vdev = vdev;
-       mutex_init(&vkbd->event_mutex);
 
        vkbd->vq = virtio_find_single_vq(vkbd->vdev, vq_keyboard_handle, "virtio-keyboard-vq");
        if (IS_ERR(vkbd->vq)) {
@@ -171,20 +146,6 @@ static int virtio_keyboard_probe(struct virtio_device *vdev)
                return ret;
        }
 
-       for (; index < KBD_BUF_SIZE; index++) {
-               sg_set_buf(&vkbd->sg[index],
-                               &vkbd->kbdevt[index],
-                               sizeof(struct EmulKbdEvent));
-       }
-
-       ret = virtqueue_add_inbuf(vkbd->vq, vkbd->sg, KBD_BUF_SIZE, (void *)vkbd->kbdevt, GFP_ATOMIC);
-       if (ret < 0) {
-               VKBD_LOG(KERN_ERR, "failed to add buffer to virtqueue.\n");
-               kfree(vkbd);
-               vdev->priv = NULL;
-               return ret;
-       }
-
        /* register for input device */
        vkbd->idev = input_allocate_device();
        if (!vkbd->idev) {
@@ -229,11 +190,22 @@ static int virtio_keyboard_probe(struct virtio_device *vdev)
                return ret;
        }
 
-       for (; index < KBD_BUF_SIZE; index++) {
-               sg_set_buf(&vkbd->sg[index],
-                               &vkbd->kbdevt[index],
-                               sizeof(struct EmulKbdEvent));
+       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;
+               }
        }
+       spin_unlock_irqrestore(&vkbd->lock, flags);
 
        virtqueue_kick(vkbd->vq);
 
@@ -242,6 +214,8 @@ static int virtio_keyboard_probe(struct virtio_device *vdev)
 
 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");
index 2619b49e6d7b71af59d3f87126d5fe6f03e339ac..5aa04f87e551006d7f6f40d3fd5c973e836601b4 100644 (file)
@@ -6,7 +6,6 @@
  * Contact:
  *  GiWoong Kim <giwoong.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
 #include <linux/virtio_config.h>
 #include <linux/kthread.h>
 
+
 MODULE_LICENSE("GPL2");
-MODULE_AUTHOR("GiWoong Kim <giwoong.kim@samsung.com>");
-MODULE_DESCRIPTION("Emulator Virtio Touchscreen driver");
+MODULE_AUTHOR("SeokYeon Hwangm <syeon.hwang@samsung.com>");
+MODULE_DESCRIPTION("Emulator virtio touchscreen driver");
 
 
 #define DEVICE_NAME "virtio-touchscreen"
 
+#define MAX_TRKID 10
+#define ABS_PRESSURE_MAX 255
+
+#define MAX_BUF_COUNT MAX_TRKID
+
+//#define DEBUG
+
 /* This structure must match the qemu definitions */
-typedef struct EmulTouchEvent {
+struct touch_event
+{
        uint16_t x, y, z;
        uint8_t state;
-} EmulTouchEvent;
-EmulTouchEvent *event;
+};
 
-typedef struct virtio_touchscreen
+struct virtio_touchscreen
 {
        struct virtio_device *vdev;
-       struct virtqueue *vq;
        struct input_dev *idev;
 
-       /* The thread servicing the touchscreen */
-       struct task_struct *thread;
-} virtio_touchscreen;
-virtio_touchscreen *vt;
-
-
-#define MAX_TRKID 10
-#define TOUCHSCREEN_RESOLUTION_X 5040
-#define TOUCHSCREEN_RESOLUTION_Y 3780
-#define ABS_PRESSURE_MAX 255
+       struct virtqueue *vq;
+       struct scatterlist sg[1];
+       struct touch_event evtbuf[MAX_BUF_COUNT];
 
-#define MAX_BUF_COUNT MAX_TRKID
-struct scatterlist sg[MAX_BUF_COUNT];
-EmulTouchEvent vbuf[MAX_BUF_COUNT];
+       spinlock_t lock;
+};
 
 static struct virtio_device_id id_table[] = {
        { VIRTIO_ID_TOUCHSCREEN, VIRTIO_DEV_ANY_ID },
@@ -82,122 +80,26 @@ static struct virtio_device_id id_table[] = {
 };
 
 
-#if 0
-/**
- * @brief : event polling
- */
-static int run_touchscreen(void *_vtouchscreen)
-{
-       virtio_touchscreen *vt = NULL;
-       int err = 0;
-       unsigned int len = 0; /* not used */
-       unsigned int index = 0;
-       unsigned int recv_index = 0;
-       unsigned int id = 0; /* finger id */
-
-       struct input_dev *input_dev = NULL;
-       EmulTouchEvent *event = NULL;
-
-       vt = (virtio_touchscreen *)_vtouchscreen;
-       input_dev = vt->idev;
-
-       sg_init_table(sg, MAX_BUF_COUNT);
-
-       for (index = 0; index < MAX_BUF_COUNT; index++) {
-               sg_set_buf(&sg[index], &vbuf[index], sizeof(EmulTouchEvent));
-
-               err = virtqueue_add_inbuf(vt->vq, sg, index + 1, (void *)index + 1, GFP_ATOMIC);
-               if (err < 0) {
-                       printk(KERN_ERR "failed to add buf\n");
-               }
-       }
-       virtqueue_kick(vt->vq);
-
-       index = 0;
-
-       while (!kthread_should_stop())
-       {
-               while ((recv_index = (unsigned int)virtqueue_get_buf(vt->vq, &len)) == 0) {
-                       cpu_relax();
-               }
-
-               do {
-                       event = &vbuf[recv_index - 1];
-#if 0
-                       printk(KERN_INFO "touch x=%d, y=%d, z=%d, state=%d, recv_index=%d\n",
-                                       event->x, event->y, event->z, event->state, recv_index);
-#endif
-
-                       id = event->z;
-
-                       /* Multi-touch Protocol is B */
-                       if (event->state != 0)
-                       { /* pressed */
-                               input_mt_slot(input_dev, id);
-                               input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, true);
-                               input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, 10);
-                               input_report_abs(input_dev, ABS_MT_POSITION_X, event->x);
-                               input_report_abs(input_dev, ABS_MT_POSITION_Y, event->y);
-                       }
-                       else
-                       { /* released */
-                               input_mt_slot(input_dev, id);
-                               input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
-                       }
-
-                       input_sync(input_dev);
-
-                       /* expose buffer to other end */
-                       err = virtqueue_add_inbuf(vt->vq, sg, recv_index, (void *)recv_index, GFP_ATOMIC);
-                       if (err < 0) {
-                               printk(KERN_ERR "failed to add buf\n");
-                       }
-
-                       recv_index = (unsigned int)virtqueue_get_buf(vt->vq, &len);
-                       if (recv_index == 0) {
-                               break;
-                       }
-               } while(true);
-
-               virtqueue_kick(vt->vq);
-       }
-
-       printk(KERN_INFO "virtio touchscreen thread is stopped\n");
-
-       return 0;
-}
-#endif
-
-
-int err;
-unsigned int len; /* not used */
-size_t buf_index;
-size_t recv_index;
-unsigned int finger_id; /* finger id */
-
 /**
  * @brief : callback for virtqueue
  */
 static void vq_touchscreen_callback(struct virtqueue *vq)
 {
-#if 0
-       printk(KERN_INFO "vq touchscreen callback\n");
+       unsigned int len; /* not used */
+       unsigned int finger_id; /* finger id */
+       struct virtio_touchscreen *vt = vq->vdev->priv;
+       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);
+#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);
 #endif
-
-       recv_index = (size_t)virtqueue_get_buf(vt->vq, &len);
-       if (recv_index == 0) {
-               printk(KERN_ERR "failed to get buffer\n");
-               return;
-       }
-
-       do {
-               event = &vbuf[recv_index - 1];
-
-#if 0
-               printk(KERN_INFO "touch x=%d, y=%d, z=%d, state=%d, recv_index=%d\n",
-                               event->x, event->y, event->z, event->state, recv_index);
-#endif
-
                finger_id = event->z;
 
                if (finger_id < MAX_TRKID) {
@@ -222,33 +124,19 @@ static void vq_touchscreen_callback(struct virtqueue *vq)
                        printk(KERN_ERR "%d is an invalid finger id!\n", finger_id);
                }
 
-               /* expose buffer to other end */
-               err = virtqueue_add_inbuf(vt->vq, sg,
-                               (unsigned int)recv_index, (void *)recv_index, GFP_ATOMIC);
+               // 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);
 
                if (err < 0) {
                        printk(KERN_ERR "failed to add buffer!\n");
                }
-
-               recv_index = (size_t)virtqueue_get_buf(vt->vq, &len);
-               if (recv_index == 0) {
-                       break;
-               }
-       } while(true);
+       }
 
        virtqueue_kick(vt->vq);
-}
-
-static int virtio_touchscreen_open(struct inode *inode, struct file *file)
-{
-       printk(KERN_INFO "virtio touchscreen device is opened\n");
-       return 0;
-}
-
-static int virtio_touchscreen_release(struct inode *inode, struct file *file)
-{
-       printk(KERN_INFO "virtio touchscreen device is closed\n");
-       return 0;
+       spin_unlock_irqrestore(&vt->lock, flags);
 }
 
 static int input_touchscreen_open(struct input_dev *dev)
@@ -262,13 +150,8 @@ static void input_touchscreen_close(struct input_dev *dev)
        printk(KERN_INFO "input touchscreen device is closed\n");
 }
 
-struct file_operations virtio_touchscreen_fops = {
-       .owner   = THIS_MODULE,
-       .open    = virtio_touchscreen_open,
-       .release = virtio_touchscreen_release,
-};
-
 extern char *saved_command_line;
+
 #define VM_RESOLUTION_KEY "vm_resolution="
 
 static int virtio_touchscreen_probe(struct virtio_device *vdev)
@@ -281,14 +164,20 @@ static int virtio_touchscreen_probe(struct virtio_device *vdev)
        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 = kmalloc(sizeof(*vt), GFP_KERNEL);
+       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,
@@ -301,27 +190,6 @@ static int virtio_touchscreen_probe(struct virtio_device *vdev)
                return ret;
        }
 
-       /* enable callback */
-       virtqueue_enable_cb(vt->vq);
-
-       sg_init_table(sg, MAX_BUF_COUNT);
-
-       /* prepare the buffers */
-       for (buf_index = 0; buf_index < MAX_BUF_COUNT; buf_index++) {
-               sg_set_buf(&sg[buf_index], &vbuf[buf_index], sizeof(EmulTouchEvent));
-
-               err = virtqueue_add_inbuf(vt->vq, sg,
-                               buf_index + 1, (void *)buf_index + 1, GFP_ATOMIC);
-
-               if (err < 0) {
-                       printk(KERN_ERR "failed to add buffer\n");
-
-                       kfree(vt);
-                       vdev->priv = NULL;
-                       return ret;
-               }
-       }
-
        cmdline = kzalloc(strlen(saved_command_line) + 1, GFP_KERNEL);
        if (cmdline) {
                /* get VM resolution */
@@ -402,48 +270,44 @@ static int virtio_touchscreen_probe(struct virtio_device *vdev)
                return ret;
        }
 
-#if 0 /* using a thread */
+       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]));
 
-       /* Responses from the hypervisor occur through the get_buf function */
-       vt->thread = kthread_run(run_touchscreen, vt, "vtouchscreen");
-       if (IS_ERR(vt->thread)) {
-               printk(KERN_ERR "unable to start the virtio touchscreen thread\n");
-               ret = PTR_ERR(vt->thread);
+               err = virtqueue_add_inbuf(vt->vq, vt->sg,
+                               1, &vt->evtbuf[index], GFP_ATOMIC);
 
-               input_mt_destroy_slots(vt->idev);
-               input_free_device(vt->idev);
-               kfree(vt);
-               vdev->priv = NULL;
-               return ret;
+               if (err < 0) {
+                       printk(KERN_ERR "failed to add buffer\n");
+
+                       kfree(vt);
+                       vdev->priv = NULL;
+                       return err;
+               }
        }
-#else /* using a callback */
+       spin_unlock_irqrestore(&vt->lock, flags);
 
        virtqueue_kick(vt->vq);
 
-       buf_index = 0;
-
-#endif
-
        return 0;
 }
 
 static void virtio_touchscreen_remove(struct virtio_device *vdev)
 {
-       virtio_touchscreen *vts = NULL;
+       struct virtio_touchscreen *vt = NULL;
 
        printk(KERN_INFO "virtio touchscreen driver is removed\n");
 
-       vts = vdev->priv;
-
-       kthread_stop(vts->thread);
+       vt = vdev->priv;
 
        vdev->config->reset(vdev); /* reset device */
        vdev->config->del_vqs(vdev); /* clean up the queues */
 
-       input_unregister_device(vts->idev);
-       input_mt_destroy_slots(vts->idev);
+       input_unregister_device(vt->idev);
+       input_mt_destroy_slots(vt->idev);
 
-       kfree(vts);
+       kfree(vt);
 }
 
 MODULE_DEVICE_TABLE(virtio, id_table);
@@ -479,4 +343,3 @@ static void __exit virtio_touchscreen_exit(void)
 
 module_init(virtio_touchscreen_init);
 module_exit(virtio_touchscreen_exit);
-