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