#include <linux/virtio.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
+#include <linux/kthread.h>
#define DEVICE_NAME "virtio-touchscreen"
uint8_t state;
} EmulTouchState;
+typedef struct virtio_touchscreen
+{
+ struct virtio_device *vdev;
+ struct virtqueue *vq;
+
+ /* The thread servicing the touchscreen */
+ struct task_struct *thread;
+} virtio_touchscreen;
+
+
+#define MAX_TRKID 6
-static struct virtqueue *vq = NULL;
static struct virtio_device_id id_table[] = {
{ VIRTIO_ID_TOUCHSCREEN, VIRTIO_DEV_ANY_ID },
{ 0 },
};
+static int run_touchscreen(void *_vtouchscreen)
+{
+ virtio_touchscreen *vt = _vtouchscreen;
+ int count = 0;
+
+ struct scatterlist sg;
+ EmulTouchState *touch = NULL;
+ EmulTouchState *buf = kzalloc(sizeof(EmulTouchState), GFP_KERNEL);
+ buf->x = MAX_TRKID;
+
+ while (!kthread_should_stop()) {
+ /* publish the real size of the buffer */
+ sg_init_one(&sg, buf, sizeof(EmulTouchState));
+
+ if (virtqueue_add_buf(vt->vq, &sg, 0, 1, (void*)buf, GFP_ATOMIC) >= 0) {
+ virtqueue_kick(vt->vq);
+
+ while (!(touch = virtqueue_get_buf(vt->vq, &count))) {
+ cpu_relax();
+ }
+
+ if (touch == NULL) {
+ printk(KERN_INFO "touch is null\n");
+ } else {
+ printk(KERN_INFO "x=%d, y=%d, z=%d, state=%d\n", touch->x, touch->y, touch->z, touch->state);
+ }
+
+ printk(KERN_INFO "virtio touchscreen remaining capacity of queue = %d\n", count);
+ }
+
+ }
+
+ printk(KERN_INFO "stop run_touchscreen\n");
+ kfree(buf);
+
+ return 0;
+}
+
static void vq_touchscreen_callback(struct virtqueue *vq)
{
printk(KERN_INFO "vq touchscreen callback\n");
static int virtio_touchscreen_probe(struct virtio_device *vdev)
{
+ struct virtio_touchscreen *vt;
int ret = 0;
printk(KERN_INFO "virtio touchscreen driver is probed.\n");
- vq = virtio_find_single_vq(vdev, NULL, "virtio-touchscreen-vq");
- if (IS_ERR(vq)) {
- return PTR_ERR(vq);
+ vdev->priv = vt = kmalloc(sizeof(*vt), GFP_KERNEL);
+ if (!vt) {
+ return -ENOMEM;
+ }
+
+ vt->vdev = vdev;
+
+ vt->vq = virtio_find_single_vq(vt->vdev, NULL, "virtio-touchscreen-vq");
+ if (IS_ERR(vt->vq)) {
+ return PTR_ERR(vt->vq);
}
ret = misc_register(&virtio_touchscreen_dev);
}
- // temp
- vq->callback = vq_touchscreen_callback;
+ // TODO:
+ vt->vq->callback = vq_touchscreen_callback;
+ virtqueue_enable_cb(vt->vq);
+
+ /* thread */
+ vt->thread = kthread_run(run_touchscreen, vt, "vtouchscreen");
+ if (IS_ERR(vt->thread)) {
+ kfree(vt);
+ return PTR_ERR(vt->thread);
+ }
- /* Transfer data */
-#if 0
- if (virtqueue_add_buf(vq, sg_list, out_page, in_page, (void*)1, GFP_ATOMIC) >= 0) {
- while (!virtqueue_get_buf(vq, &count)) {
- cpu_relax();
- }
- }
-#endif
return 0;
}
static void __devexit virtio_touchscreen_remove(struct virtio_device *vdev)
{
+ virtio_touchscreen *vt;
+
printk(KERN_INFO "virtio touchscreen driver is removed.\n");
+ vt = vdev->priv;
+
+ kthread_stop(vt->thread);
+
vdev->config->reset(vdev); // reset device
misc_deregister(&virtio_touchscreen_dev);
vdev->config->del_vqs(vdev); // clean up the queues
+
+ kfree(vt);
}
static struct virtio_driver virtio_touchscreen_driver = {