linux/arch/um/drivers/random.c
<<
>>
Prefs
   1/* Copyright (C) 2005 - 2008 Jeff Dike <jdike@{linux.intel,addtoit}.com> */
   2
   3/* Much of this ripped from drivers/char/hw_random.c, see there for other
   4 * copyright.
   5 *
   6 * This software may be used and distributed according to the terms
   7 * of the GNU General Public License, incorporated herein by reference.
   8 */
   9#include <linux/sched/signal.h>
  10#include <linux/module.h>
  11#include <linux/fs.h>
  12#include <linux/interrupt.h>
  13#include <linux/miscdevice.h>
  14#include <linux/hw_random.h>
  15#include <linux/delay.h>
  16#include <linux/uaccess.h>
  17#include <init.h>
  18#include <irq_kern.h>
  19#include <os.h>
  20
  21/*
  22 * core module information
  23 */
  24#define RNG_MODULE_NAME "hw_random"
  25
  26/* Changed at init time, in the non-modular case, and at module load
  27 * time, in the module case.  Presumably, the module subsystem
  28 * protects against a module being loaded twice at the same time.
  29 */
  30static int random_fd = -1;
  31static struct hwrng hwrng = { 0, };
  32static DECLARE_COMPLETION(have_data);
  33
  34static int rng_dev_read(struct hwrng *rng, void *buf, size_t max, bool block)
  35{
  36        int ret;
  37
  38        for (;;) {
  39                ret = os_read_file(random_fd, buf, max);
  40                if (block && ret == -EAGAIN) {
  41                        add_sigio_fd(random_fd);
  42
  43                        ret = wait_for_completion_killable(&have_data);
  44
  45                        ignore_sigio_fd(random_fd);
  46                        deactivate_fd(random_fd, RANDOM_IRQ);
  47
  48                        if (ret < 0)
  49                                break;
  50                } else {
  51                        break;
  52                }
  53        }
  54
  55        return ret != -EAGAIN ? ret : 0;
  56}
  57
  58static irqreturn_t random_interrupt(int irq, void *data)
  59{
  60        complete(&have_data);
  61
  62        return IRQ_HANDLED;
  63}
  64
  65/*
  66 * rng_init - initialize RNG module
  67 */
  68static int __init rng_init (void)
  69{
  70        int err;
  71
  72        err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
  73        if (err < 0)
  74                goto out;
  75
  76        random_fd = err;
  77        err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt,
  78                             0, "random", NULL);
  79        if (err < 0)
  80                goto err_out_cleanup_hw;
  81
  82        sigio_broken(random_fd);
  83        hwrng.name = RNG_MODULE_NAME;
  84        hwrng.read = rng_dev_read;
  85        hwrng.quality = 1024;
  86
  87        err = hwrng_register(&hwrng);
  88        if (err) {
  89                pr_err(RNG_MODULE_NAME " registering failed (%d)\n", err);
  90                goto err_out_cleanup_hw;
  91        }
  92out:
  93        return err;
  94
  95err_out_cleanup_hw:
  96        os_close_file(random_fd);
  97        random_fd = -1;
  98        goto out;
  99}
 100
 101/*
 102 * rng_cleanup - shutdown RNG module
 103 */
 104
 105static void cleanup(void)
 106{
 107        free_irq_by_fd(random_fd);
 108        os_close_file(random_fd);
 109}
 110
 111static void __exit rng_cleanup(void)
 112{
 113        hwrng_unregister(&hwrng);
 114        os_close_file(random_fd);
 115}
 116
 117module_init (rng_init);
 118module_exit (rng_cleanup);
 119__uml_exitcall(cleanup);
 120
 121MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
 122MODULE_LICENSE("GPL");
 123