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/delay.h>
  15#include <linux/uaccess.h>
  16#include <irq_kern.h>
  17#include <os.h>
  18
  19/*
  20 * core module and version information
  21 */
  22#define RNG_VERSION "1.0.0"
  23#define RNG_MODULE_NAME "hw_random"
  24
  25#define RNG_MISCDEV_MINOR               183 /* official */
  26
  27/* Changed at init time, in the non-modular case, and at module load
  28 * time, in the module case.  Presumably, the module subsystem
  29 * protects against a module being loaded twice at the same time.
  30 */
  31static int random_fd = -1;
  32static DECLARE_WAIT_QUEUE_HEAD(host_read_wait);
  33
  34static int rng_dev_open (struct inode *inode, struct file *filp)
  35{
  36        /* enforce read-only access to this chrdev */
  37        if ((filp->f_mode & FMODE_READ) == 0)
  38                return -EINVAL;
  39        if ((filp->f_mode & FMODE_WRITE) != 0)
  40                return -EINVAL;
  41
  42        return 0;
  43}
  44
  45static atomic_t host_sleep_count = ATOMIC_INIT(0);
  46
  47static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
  48                             loff_t *offp)
  49{
  50        u32 data;
  51        int n, ret = 0, have_data;
  52
  53        while (size) {
  54                n = os_read_file(random_fd, &data, sizeof(data));
  55                if (n > 0) {
  56                        have_data = n;
  57                        while (have_data && size) {
  58                                if (put_user((u8) data, buf++)) {
  59                                        ret = ret ? : -EFAULT;
  60                                        break;
  61                                }
  62                                size--;
  63                                ret++;
  64                                have_data--;
  65                                data >>= 8;
  66                        }
  67                }
  68                else if (n == -EAGAIN) {
  69                        DECLARE_WAITQUEUE(wait, current);
  70
  71                        if (filp->f_flags & O_NONBLOCK)
  72                                return ret ? : -EAGAIN;
  73
  74                        atomic_inc(&host_sleep_count);
  75                        reactivate_fd(random_fd, RANDOM_IRQ);
  76                        add_sigio_fd(random_fd);
  77
  78                        add_wait_queue(&host_read_wait, &wait);
  79                        set_current_state(TASK_INTERRUPTIBLE);
  80
  81                        schedule();
  82                        remove_wait_queue(&host_read_wait, &wait);
  83
  84                        if (atomic_dec_and_test(&host_sleep_count)) {
  85                                ignore_sigio_fd(random_fd);
  86                                deactivate_fd(random_fd, RANDOM_IRQ);
  87                        }
  88                }
  89                else
  90                        return n;
  91
  92                if (signal_pending (current))
  93                        return ret ? : -ERESTARTSYS;
  94        }
  95        return ret;
  96}
  97
  98static const struct file_operations rng_chrdev_ops = {
  99        .owner          = THIS_MODULE,
 100        .open           = rng_dev_open,
 101        .read           = rng_dev_read,
 102        .llseek         = noop_llseek,
 103};
 104
 105/* rng_init shouldn't be called more than once at boot time */
 106static struct miscdevice rng_miscdev = {
 107        RNG_MISCDEV_MINOR,
 108        RNG_MODULE_NAME,
 109        &rng_chrdev_ops,
 110};
 111
 112static irqreturn_t random_interrupt(int irq, void *data)
 113{
 114        wake_up(&host_read_wait);
 115
 116        return IRQ_HANDLED;
 117}
 118
 119/*
 120 * rng_init - initialize RNG module
 121 */
 122static int __init rng_init (void)
 123{
 124        int err;
 125
 126        err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0);
 127        if (err < 0)
 128                goto out;
 129
 130        random_fd = err;
 131
 132        err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt,
 133                             0, "random", NULL);
 134        if (err)
 135                goto err_out_cleanup_hw;
 136
 137        sigio_broken(random_fd, 1);
 138
 139        err = misc_register (&rng_miscdev);
 140        if (err) {
 141                printk (KERN_ERR RNG_MODULE_NAME ": misc device register "
 142                        "failed\n");
 143                goto err_out_cleanup_hw;
 144        }
 145out:
 146        return err;
 147
 148err_out_cleanup_hw:
 149        os_close_file(random_fd);
 150        random_fd = -1;
 151        goto out;
 152}
 153
 154/*
 155 * rng_cleanup - shutdown RNG module
 156 */
 157static void __exit rng_cleanup (void)
 158{
 159        os_close_file(random_fd);
 160        misc_deregister (&rng_miscdev);
 161}
 162
 163module_init (rng_init);
 164module_exit (rng_cleanup);
 165
 166MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
 167MODULE_LICENSE("GPL");
 168