Commit | Line | Data |
---|---|---|
567b5650 PBG |
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 | */ | |
1da177e4 LT |
8 | #include <linux/module.h> |
9 | #include <linux/fs.h> | |
10 | #include <linux/miscdevice.h> | |
11 | #include <linux/delay.h> | |
12 | #include <asm/uaccess.h> | |
13 | #include "os.h" | |
14 | ||
15 | /* | |
16 | * core module and version information | |
17 | */ | |
18 | #define RNG_VERSION "1.0.0" | |
19 | #define RNG_MODULE_NAME "random" | |
1da177e4 LT |
20 | |
21 | #define RNG_MISCDEV_MINOR 183 /* official */ | |
22 | ||
23 | static int random_fd = -1; | |
24 | ||
25 | static int rng_dev_open (struct inode *inode, struct file *filp) | |
26 | { | |
27 | /* enforce read-only access to this chrdev */ | |
28 | if ((filp->f_mode & FMODE_READ) == 0) | |
29 | return -EINVAL; | |
30 | if (filp->f_mode & FMODE_WRITE) | |
31 | return -EINVAL; | |
32 | ||
33 | return 0; | |
34 | } | |
35 | ||
36 | static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, | |
37 | loff_t * offp) | |
38 | { | |
39 | u32 data; | |
40 | int n, ret = 0, have_data; | |
41 | ||
42 | while(size){ | |
43 | n = os_read_file(random_fd, &data, sizeof(data)); | |
44 | if(n > 0){ | |
45 | have_data = n; | |
46 | while (have_data && size) { | |
47 | if (put_user((u8)data, buf++)) { | |
48 | ret = ret ? : -EFAULT; | |
49 | break; | |
50 | } | |
51 | size--; | |
52 | ret++; | |
53 | have_data--; | |
54 | data>>=8; | |
55 | } | |
56 | } | |
57 | else if(n == -EAGAIN){ | |
58 | if (filp->f_flags & O_NONBLOCK) | |
59 | return ret ? : -EAGAIN; | |
60 | ||
61 | if(need_resched()){ | |
62 | current->state = TASK_INTERRUPTIBLE; | |
63 | schedule_timeout(1); | |
64 | } | |
65 | } | |
66 | else return n; | |
67 | if (signal_pending (current)) | |
68 | return ret ? : -ERESTARTSYS; | |
69 | } | |
70 | return ret; | |
71 | } | |
72 | ||
73 | static struct file_operations rng_chrdev_ops = { | |
74 | .owner = THIS_MODULE, | |
75 | .open = rng_dev_open, | |
76 | .read = rng_dev_read, | |
77 | }; | |
78 | ||
79 | static struct miscdevice rng_miscdev = { | |
80 | RNG_MISCDEV_MINOR, | |
81 | RNG_MODULE_NAME, | |
82 | &rng_chrdev_ops, | |
83 | }; | |
84 | ||
85 | /* | |
86 | * rng_init - initialize RNG module | |
87 | */ | |
88 | static int __init rng_init (void) | |
89 | { | |
90 | int err; | |
91 | ||
92 | err = os_open_file("/dev/random", of_read(OPENFLAGS()), 0); | |
93 | if(err < 0) | |
94 | goto out; | |
95 | ||
96 | random_fd = err; | |
97 | ||
98 | err = os_set_fd_block(random_fd, 0); | |
99 | if(err) | |
100 | goto err_out_cleanup_hw; | |
101 | ||
102 | err = misc_register (&rng_miscdev); | |
103 | if (err) { | |
567b5650 | 104 | printk (KERN_ERR RNG_MODULE_NAME ": misc device register failed\n"); |
1da177e4 LT |
105 | goto err_out_cleanup_hw; |
106 | } | |
107 | ||
108 | out: | |
109 | return err; | |
110 | ||
111 | err_out_cleanup_hw: | |
112 | random_fd = -1; | |
113 | goto out; | |
114 | } | |
115 | ||
116 | /* | |
117 | * rng_cleanup - shutdown RNG module | |
118 | */ | |
119 | static void __exit rng_cleanup (void) | |
120 | { | |
121 | misc_deregister (&rng_miscdev); | |
122 | } | |
123 | ||
124 | module_init (rng_init); | |
125 | module_exit (rng_cleanup); | |
567b5650 PBG |
126 | |
127 | MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver"); | |
128 | MODULE_LICENSE("GPL"); |