xref: /kvm-unit-tests/lib/chr-testdev.c (revision 0df901e0379da84a0eaec1daf464c699995dddf5)
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 #include "chr-testdev.h"
11 
12 #define TESTDEV_NAME "chr-testdev"
13 
14 static struct virtio_device *vcon;
15 static struct virtqueue *in_vq, *out_vq;
16 static struct spinlock lock;
17 
18 static void __testdev_send(char *buf, unsigned int len)
19 {
20 	int ret;
21 
22 	ret = virtqueue_add_outbuf(out_vq, buf, len);
23 	virtqueue_kick(out_vq);
24 
25 	if (ret < 0)
26 		return;
27 
28 	while (!virtqueue_get_buf(out_vq, &len))
29 		;
30 }
31 
32 void chr_testdev_exit(int code)
33 {
34 	unsigned int len;
35 	static char buf[8];
36 
37 	spin_lock(&lock);
38 	if (!vcon)
39 		goto out;
40 
41 	snprintf(buf, sizeof(buf), "%dq", code);
42 	len = strlen(buf);
43 
44 	__testdev_send(buf, len);
45 
46 out:
47 	spin_unlock(&lock);
48 }
49 
50 void chr_testdev_init(void)
51 {
52 	const char *io_names[] = { "input", "output" };
53 	struct virtqueue *vqs[2];
54 	int ret;
55 
56 	vcon = virtio_bind(VIRTIO_ID_CONSOLE);
57 	if (vcon == NULL) {
58 		printf("%s: %s: can't find a virtio-console\n",
59 				__func__, TESTDEV_NAME);
60 		return;
61 	}
62 
63 	ret = vcon->config->find_vqs(vcon, 2, vqs, NULL, io_names);
64 	if (ret < 0) {
65 		printf("%s: %s: can't init virtqueues\n",
66 				__func__, TESTDEV_NAME);
67 		vcon = NULL;
68 		return;
69 	}
70 
71 	in_vq = vqs[0];
72 	out_vq = vqs[1];
73 }
74