From: SeokYeon Hwang Date: Wed, 22 Jun 2016 06:17:32 +0000 (+0900) Subject: virtio: introduce maru_virtio_device X-Git-Tag: submit/tizen/20161219.112149~11^2~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=37bd14836f536df795a70fb8dab279d8da437d93;p=sdk%2Femulator%2Femulator-kernel.git virtio: introduce maru_virtio_device "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 (cherry picked from commit ee8604f9a69db762f0618851352e3979010ed181) --- diff --git a/drivers/maru/maru_virtio_device.h b/drivers/maru/maru_virtio_device.h new file mode 100644 index 000000000000..42eb148c2fe3 --- /dev/null +++ b/drivers/maru/maru_virtio_device.h @@ -0,0 +1,98 @@ +/* + * Maru Virtio Input Device Driver + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * SeokYeon Hwang + * GiWoong Kim + * + * 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 diff --git a/drivers/maru/maru_virtio_hwkey.c b/drivers/maru/maru_virtio_hwkey.c index 03f30eb21bd1..3dd36051c6cc 100644 --- a/drivers/maru/maru_virtio_hwkey.c +++ b/drivers/maru/maru_virtio_hwkey.c @@ -4,9 +4,8 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: + * SeokYeon Hwang * 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 @@ -39,33 +38,27 @@ #include #include +#include "maru_virtio_device.h" + MODULE_LICENSE("GPL2"); -MODULE_AUTHOR("Sungmin Ha "); +MODULE_AUTHOR("SeokYeon Hwangm "); 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); - diff --git a/drivers/maru/maru_virtio_keyboard.c b/drivers/maru/maru_virtio_keyboard.c index a358493b128f..66db8fc0b8b6 100644 --- a/drivers/maru/maru_virtio_keyboard.c +++ b/drivers/maru/maru_virtio_keyboard.c @@ -4,8 +4,8 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: - * GiWoong Kim * SeokYeon Hwang + * GiWoong Kim * * 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 #include +#include "maru_virtio_device.h" MODULE_LICENSE("GPL2"); MODULE_AUTHOR("SeokYeon Hwangm "); @@ -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); diff --git a/drivers/maru/maru_virtio_touchscreen.c b/drivers/maru/maru_virtio_touchscreen.c index 5aa04f87e551..1e5650eb69a4 100644 --- a/drivers/maru/maru_virtio_touchscreen.c +++ b/drivers/maru/maru_virtio_touchscreen.c @@ -4,8 +4,8 @@ * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: - * GiWoong Kim * SeokYeon Hwang + * GiWoong Kim * * 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 #include +#include "maru_virtio_device.h" MODULE_LICENSE("GPL2"); MODULE_AUTHOR("SeokYeon Hwangm "); @@ -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);