1b412ad0dSAndrew Jones /*
2b412ad0dSAndrew Jones * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
3b412ad0dSAndrew Jones *
4b412ad0dSAndrew Jones * This work is licensed under the terms of the GNU LGPL, version 2.
5b412ad0dSAndrew Jones */
6b412ad0dSAndrew Jones #include "libcflat.h"
7b412ad0dSAndrew Jones #include "virtio.h"
8b412ad0dSAndrew Jones #include "asm/spinlock.h"
9b412ad0dSAndrew Jones
100df901e0SAndrew Jones #include "chr-testdev.h"
110df901e0SAndrew Jones
12b412ad0dSAndrew Jones #define TESTDEV_NAME "chr-testdev"
13b412ad0dSAndrew Jones
14b412ad0dSAndrew Jones static struct virtio_device *vcon;
15b412ad0dSAndrew Jones static struct virtqueue *in_vq, *out_vq;
16b412ad0dSAndrew Jones static struct spinlock lock;
17b412ad0dSAndrew Jones
__testdev_send(char * buf,unsigned int len)18368819a9SAndrew Jones static void __testdev_send(char *buf, unsigned int len)
19b412ad0dSAndrew Jones {
20b412ad0dSAndrew Jones int ret;
21b412ad0dSAndrew Jones
22b412ad0dSAndrew Jones ret = virtqueue_add_outbuf(out_vq, buf, len);
23b412ad0dSAndrew Jones virtqueue_kick(out_vq);
24b412ad0dSAndrew Jones
25b412ad0dSAndrew Jones if (ret < 0)
26b412ad0dSAndrew Jones return;
27b412ad0dSAndrew Jones
28b412ad0dSAndrew Jones while (!virtqueue_get_buf(out_vq, &len))
29b412ad0dSAndrew Jones ;
30b412ad0dSAndrew Jones }
31b412ad0dSAndrew Jones
chr_testdev_exit(int code)32b412ad0dSAndrew Jones void chr_testdev_exit(int code)
33b412ad0dSAndrew Jones {
34368819a9SAndrew Jones unsigned int len;
3516444ac8SPaolo Bonzini static char buf[8];
3616444ac8SPaolo Bonzini
3716444ac8SPaolo Bonzini spin_lock(&lock);
3816444ac8SPaolo Bonzini if (!vcon)
3916444ac8SPaolo Bonzini goto out;
40b412ad0dSAndrew Jones
41b412ad0dSAndrew Jones snprintf(buf, sizeof(buf), "%dq", code);
42b412ad0dSAndrew Jones len = strlen(buf);
43b412ad0dSAndrew Jones
44b412ad0dSAndrew Jones __testdev_send(buf, len);
45b412ad0dSAndrew Jones
46b412ad0dSAndrew Jones out:
47b412ad0dSAndrew Jones spin_unlock(&lock);
48b412ad0dSAndrew Jones }
49b412ad0dSAndrew Jones
chr_testdev_init(void)50b412ad0dSAndrew Jones void chr_testdev_init(void)
51b412ad0dSAndrew Jones {
52b412ad0dSAndrew Jones const char *io_names[] = { "input", "output" };
53b412ad0dSAndrew Jones struct virtqueue *vqs[2];
54b412ad0dSAndrew Jones int ret;
55b412ad0dSAndrew Jones
56b412ad0dSAndrew Jones vcon = virtio_bind(VIRTIO_ID_CONSOLE);
57*5786c838SAndrew Jones if (vcon == NULL)
58b412ad0dSAndrew Jones return;
59b412ad0dSAndrew Jones
60b412ad0dSAndrew Jones ret = vcon->config->find_vqs(vcon, 2, vqs, NULL, io_names);
61b412ad0dSAndrew Jones if (ret < 0) {
62b412ad0dSAndrew Jones printf("%s: %s: can't init virtqueues\n",
63b412ad0dSAndrew Jones __func__, TESTDEV_NAME);
64b412ad0dSAndrew Jones vcon = NULL;
65b412ad0dSAndrew Jones return;
66b412ad0dSAndrew Jones }
67b412ad0dSAndrew Jones
68b412ad0dSAndrew Jones in_vq = vqs[0];
69b412ad0dSAndrew Jones out_vq = vqs[1];
70b412ad0dSAndrew Jones }
71