xref: /kvm-unit-tests/lib/chr-testdev.c (revision 71a6a145226927f50d938b0f2befc24363a496bc)
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, unsigned int 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 	unsigned int len;
33 	static char buf[8];
34 
35 	spin_lock(&lock);
36 	if (!vcon)
37 		goto out;
38 
39 	snprintf(buf, sizeof(buf), "%dq", code);
40 	len = strlen(buf);
41 
42 	__testdev_send(buf, len);
43 
44 out:
45 	spin_unlock(&lock);
46 }
47 
48 void chr_testdev_init(void)
49 {
50 	const char *io_names[] = { "input", "output" };
51 	struct virtqueue *vqs[2];
52 	int ret;
53 
54 	vcon = virtio_bind(VIRTIO_ID_CONSOLE);
55 	if (vcon == NULL) {
56 		printf("%s: %s: can't find a virtio-console\n",
57 				__func__, TESTDEV_NAME);
58 		return;
59 	}
60 
61 	ret = vcon->config->find_vqs(vcon, 2, vqs, NULL, io_names);
62 	if (ret < 0) {
63 		printf("%s: %s: can't init virtqueues\n",
64 				__func__, TESTDEV_NAME);
65 		vcon = NULL;
66 		return;
67 	}
68 
69 	in_vq = vqs[0];
70 	out_vq = vqs[1];
71 }
72