xref: /kvm-unit-tests/lib/chr-testdev.c (revision 74ff0e9675ec6d9477f5e98ec7d5d50878fa7ebc)
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 
__testdev_send(char * buf,unsigned int len)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 
chr_testdev_exit(int code)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 
chr_testdev_init(void)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 		return;
59 
60 	ret = vcon->config->find_vqs(vcon, 2, vqs, NULL, io_names);
61 	if (ret < 0) {
62 		printf("%s: %s: can't init virtqueues\n",
63 				__func__, TESTDEV_NAME);
64 		vcon = NULL;
65 		return;
66 	}
67 
68 	in_vq = vqs[0];
69 	out_vq = vqs[1];
70 }
71