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