1 /* Copyright (C) 2005 Jeff Dike <jdike@addtoit.com> */ 2 /* Much of this ripped from drivers/char/hw_random.c, see there for other 3 * copyright. 4 * 5 * This software may be used and distributed according to the terms 6 * of the GNU General Public License, incorporated herein by reference. 7 */ 8 #include <linux/sched.h> 9 #include <linux/module.h> 10 #include <linux/fs.h> 11 #include <linux/miscdevice.h> 12 #include <linux/delay.h> 13 #include <asm/uaccess.h> 14 #include "os.h" 15 16 /* 17 * core module and version information 18 */ 19 #define RNG_VERSION "1.0.0" 20 #define RNG_MODULE_NAME "random" 21 22 #define RNG_MISCDEV_MINOR 183 /* official */ 23 24 /* Changed at init time, in the non-modular case, and at module load 25 * time, in the module case. Presumably, the module subsystem 26 * protects against a module being loaded twice at the same time. 27 */ 28 static int random_fd = -1; 29 30 static int rng_dev_open (struct inode *inode, struct file *filp) 31 { 32 /* enforce read-only access to this chrdev */ 33 if ((filp->f_mode & FMODE_READ) == 0) 34 return -EINVAL; 35 if (filp->f_mode & FMODE_WRITE) 36 return -EINVAL; 37 38 return 0; 39 } 40 41 static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, 42 loff_t * offp) 43 { 44 u32 data; 45 int n, ret = 0, have_data; 46 47 while(size){ 48 n = os_read_file(random_fd, &data, sizeof(data)); 49 if(n > 0){ 50 have_data = n; 51 while (have_data && size) { 52 if (put_user((u8)data, buf++)) { 53 ret = ret ? : -EFAULT; 54 break; 55 } 56 size--; 57 ret++; 58 have_data--; 59 data>>=8; 60 } 61 } 62 else if(n == -EAGAIN){ 63 if (filp->f_flags & O_NONBLOCK) 64 return ret ? : -EAGAIN; 65 66 if(need_resched()) 67 schedule_timeout_interruptible(1); 68 } 69 else return n; 70 if (signal_pending (current)) 71 return ret ? : -ERESTARTSYS; 72 } 73 return ret; 74 } 75 76 static const struct file_operations rng_chrdev_ops = { 77 .owner = THIS_MODULE, 78 .open = rng_dev_open, 79 .read = rng_dev_read, 80 }; 81 82 /* rng_init shouldn't be called more than once at boot time */ 83 static struct miscdevice rng_miscdev = { 84 RNG_MISCDEV_MINOR, 85 RNG_MODULE_NAME, 86 &rng_chrdev_ops, 87 }; 88 89 /* 90 * rng_init - initialize RNG module 91 */ 92 static int __init rng_init (void) 93 { 94 int err; 95 96 err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0); 97 if(err < 0) 98 goto out; 99 100 random_fd = err; 101 102 err = os_set_fd_block(random_fd, 0); 103 if(err) 104 goto err_out_cleanup_hw; 105 106 err = misc_register (&rng_miscdev); 107 if (err) { 108 printk (KERN_ERR RNG_MODULE_NAME ": misc device register failed\n"); 109 goto err_out_cleanup_hw; 110 } 111 112 out: 113 return err; 114 115 err_out_cleanup_hw: 116 random_fd = -1; 117 goto out; 118 } 119 120 /* 121 * rng_cleanup - shutdown RNG module 122 */ 123 static void __exit rng_cleanup (void) 124 { 125 misc_deregister (&rng_miscdev); 126 } 127 128 module_init (rng_init); 129 module_exit (rng_cleanup); 130 131 MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver"); 132 MODULE_LICENSE("GPL"); 133