From 91eaaec79ad68aad3d7444649bcc59aa60b16303 Mon Sep 17 00:00:00 2001 From: SeokYeon Hwang Date: Wed, 15 Jun 2016 17:35:10 +0900 Subject: [PATCH] input: rewrite virtio touchscreen / keyboard device Simplified input processing logics. Used proper virtio APIs. Change-Id: I24a8564842fbb0d3833c4c2bf21e658c85c00cb0 Signed-off-by: SeokYeon Hwang --- drivers/maru/maru_virtio_keyboard.c | 140 ++++++------- drivers/maru/maru_virtio_touchscreen.c | 271 ++++++------------------- 2 files changed, 124 insertions(+), 287 deletions(-) diff --git a/drivers/maru/maru_virtio_keyboard.c b/drivers/maru/maru_virtio_keyboard.c index f318ef153a84..a358493b128f 100644 --- a/drivers/maru/maru_virtio_keyboard.c +++ b/drivers/maru/maru_virtio_keyboard.c @@ -4,9 +4,8 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: - * Kitae Kim + * GiWoong Kim * SeokYeon Hwang - * YeongKyoon Lee * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -39,16 +38,20 @@ #include #include + MODULE_LICENSE("GPL2"); -MODULE_AUTHOR("Kitae Kim "); -MODULE_DESCRIPTION("Emulator Virtio Keyboard Driver"); +MODULE_AUTHOR("SeokYeon Hwangm "); +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"); diff --git a/drivers/maru/maru_virtio_touchscreen.c b/drivers/maru/maru_virtio_touchscreen.c index 2619b49e6d7b..5aa04f87e551 100644 --- a/drivers/maru/maru_virtio_touchscreen.c +++ b/drivers/maru/maru_virtio_touchscreen.c @@ -6,7 +6,6 @@ * Contact: * GiWoong Kim * SeokYeon Hwang - * YeongKyoon Lee * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -41,40 +40,39 @@ #include #include + MODULE_LICENSE("GPL2"); -MODULE_AUTHOR("GiWoong Kim "); -MODULE_DESCRIPTION("Emulator Virtio Touchscreen driver"); +MODULE_AUTHOR("SeokYeon Hwangm "); +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); - -- 2.34.1