123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- /* Copyright (C) 2005 - 2008 Jeff Dike <jdike@{linux.intel,addtoit}.com> */
- /* Much of this ripped from drivers/char/hw_random.c, see there for other
- * copyright.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
- #include <linux/sched/signal.h>
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/interrupt.h>
- #include <linux/miscdevice.h>
- #include <linux/hw_random.h>
- #include <linux/delay.h>
- #include <linux/uaccess.h>
- #include <init.h>
- #include <irq_kern.h>
- #include <os.h>
- /*
- * core module information
- */
- #define RNG_MODULE_NAME "hw_random"
- /* Changed at init time, in the non-modular case, and at module load
- * time, in the module case. Presumably, the module subsystem
- * protects against a module being loaded twice at the same time.
- */
- static int random_fd = -1;
- static struct hwrng hwrng;
- static DECLARE_COMPLETION(have_data);
- static int rng_dev_read(struct hwrng *rng, void *buf, size_t max, bool block)
- {
- int ret;
- for (;;) {
- ret = os_read_file(random_fd, buf, max);
- if (block && ret == -EAGAIN) {
- add_sigio_fd(random_fd);
- ret = wait_for_completion_killable(&have_data);
- ignore_sigio_fd(random_fd);
- deactivate_fd(random_fd, RANDOM_IRQ);
- if (ret < 0)
- break;
- } else {
- break;
- }
- }
- return ret != -EAGAIN ? ret : 0;
- }
- static irqreturn_t random_interrupt(int irq, void *data)
- {
- complete(&have_data);
- return IRQ_HANDLED;
- }
- /*
- * rng_init - initialize RNG module
- */
- static int __init rng_init (void)
- {
- int err;
- err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
- if (err < 0)
- goto out;
- random_fd = err;
- err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt,
- 0, "random", NULL);
- if (err < 0)
- goto err_out_cleanup_hw;
- sigio_broken(random_fd);
- hwrng.name = RNG_MODULE_NAME;
- hwrng.read = rng_dev_read;
- hwrng.quality = 1024;
- err = hwrng_register(&hwrng);
- if (err) {
- pr_err(RNG_MODULE_NAME " registering failed (%d)\n", err);
- goto err_out_cleanup_hw;
- }
- out:
- return err;
- err_out_cleanup_hw:
- os_close_file(random_fd);
- random_fd = -1;
- goto out;
- }
- /*
- * rng_cleanup - shutdown RNG module
- */
- static void cleanup(void)
- {
- free_irq_by_fd(random_fd);
- os_close_file(random_fd);
- }
- static void __exit rng_cleanup(void)
- {
- hwrng_unregister(&hwrng);
- os_close_file(random_fd);
- }
- module_init (rng_init);
- module_exit (rng_cleanup);
- __uml_exitcall(cleanup);
- MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
- MODULE_LICENSE("GPL");
|