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