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