aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authoracirillo87 <acirillo87@35acf78f-673a-0410-8e92-d51de3d6d3f4>2013-07-31 13:25:46 +0000
committeracirillo87 <acirillo87@35acf78f-673a-0410-8e92-d51de3d6d3f4>2013-07-31 13:25:46 +0000
commit6acc48bc50785ef5d8eaf2fdf11ac229489edad9 (patch)
tree41d196ee1d17d0a85b280a1a65e59206220612cb /docs
parent16c83514ae6459e4ef2395ad22f32f1d8713a17b (diff)
downloadChibiOS-6acc48bc50785ef5d8eaf2fdf11ac229489edad9.tar.gz
ChibiOS-6acc48bc50785ef5d8eaf2fdf11ac229489edad9.tar.bz2
ChibiOS-6acc48bc50785ef5d8eaf2fdf11ac229489edad9.zip
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@6057 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'docs')
0 files changed, 0 insertions, 0 deletions
id='n102' href='#n102'>102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
/*
 * Randomness driver for virtio
 *  Copyright (C) 2007, 2008 Rusty Russell IBM Corporation
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */

#include <linux/err.h>
#include <linux/hw_random.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
#include <linux/virtio.h>
#include <linux/virtio_rng.h>

static struct virtqueue *vq;
static unsigned int data_avail;
static DECLARE_COMPLETION(have_data);
static bool busy;

static void random_recv_done(struct virtqueue *vq)
{
	/* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
	if (!virtqueue_get_buf(vq, &data_avail))
		return;

	complete(&have_data);
}

/* The host will fill any buffer we give it with sweet, sweet randomness. */
static void register_buffer(u8 *buf, size_t size)
{
	struct scatterlist sg;

	sg_init_one(&sg, buf, size);

	/* There should always be room for one buffer. */
	if (virtqueue_add_buf(vq, &sg, 0, 1, buf) < 0)
		BUG();

	virtqueue_kick(vq);
}

static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
{

	if (!busy) {
		busy = true;
		init_completion(&have_data);
		register_buffer(buf, size);
	}

	if (!wait)
		return 0;

	wait_for_completion(&have_data);

	busy = false;

	return data_avail;
}

static void virtio_cleanup(struct hwrng *rng)
{
	if (busy)
		wait_for_completion(&have_data);
}


static struct hwrng virtio_hwrng = {
	.name		= "virtio",
	.cleanup	= virtio_cleanup,
	.read		= virtio_read,
};

static int virtrng_probe(struct virtio_device *vdev)
{
	int err;

	/* We expect a single virtqueue. */
	vq = virtio_find_single_vq(vdev, random_recv_done, "input");
	if (IS_ERR(vq))
		return PTR_ERR(vq);

	err = hwrng_register(&virtio_hwrng);
	if (err) {
		vdev->config->del_vqs(vdev);
		return err;
	}

	return 0;
}

static void __devexit virtrng_remove(struct virtio_device *vdev)
{
	vdev->config->reset(vdev);
	hwrng_unregister(&virtio_hwrng);
	vdev->config->del_vqs(vdev);
}

static struct virtio_device_id id_table[] = {
	{ VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },
	{ 0 },
};

static struct virtio_driver virtio_rng_driver = {
	.driver.name =	KBUILD_MODNAME,
	.driver.owner =	THIS_MODULE,
	.id_table =	id_table,
	.probe =	virtrng_probe,
	.remove =	__devexit_p(virtrng_remove),
};

static int __init init(void)
{
	return register_virtio_driver(&virtio_rng_driver);
}

static void __exit fini(void)
{
	unregister_virtio_driver(&virtio_rng_driver);
}
module_init(init);
module_exit(fini);

MODULE_DEVICE_TABLE(virtio, id_table);
MODULE_DESCRIPTION("Virtio random number driver");
MODULE_LICENSE("GPL");