2 Added support for the AMD Geode LX RNG
3 (c) Copyright 2004-2005 Advanced Micro Devices, Inc.
7 Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
12 Hardware driver for the AMD 768 Random Number Generator (RNG)
17 Hardware driver for Intel i810 Random Number Generator (RNG)
23 Copyright 2005 (c) MontaVista Software, Inc.
25 Please read Documentation/hw_random.txt for details on use.
27 ----------------------------------------------------------
28 This software may be used and distributed according to the terms
29 of the GNU General Public License, incorporated herein by reference.
34 #include <linux/device.h>
35 #include <linux/hw_random.h>
36 #include <linux/module.h>
37 #include <linux/kernel.h>
39 #include <linux/sched.h>
40 #include <linux/smp_lock.h>
41 #include <linux/init.h>
42 #include <linux/miscdevice.h>
43 #include <linux/delay.h>
44 #include <asm/uaccess.h>
47 #define RNG_MODULE_NAME "hw_random"
48 #define PFX RNG_MODULE_NAME ": "
49 #define RNG_MISCDEV_MINOR 183 /* official */
52 static struct hwrng *current_rng;
53 static LIST_HEAD(rng_list);
54 static DEFINE_MUTEX(rng_mutex);
55 static int data_avail;
56 static u8 rng_buffer[SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES]
59 static inline int hwrng_init(struct hwrng *rng)
63 return rng->init(rng);
66 static inline void hwrng_cleanup(struct hwrng *rng)
68 if (rng && rng->cleanup)
72 static int rng_dev_open(struct inode *inode, struct file *filp)
74 /* enforce read-only access to this chrdev */
75 if ((filp->f_mode & FMODE_READ) == 0)
77 if (filp->f_mode & FMODE_WRITE)
82 static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
87 return rng->read(rng, (void *)buffer, size, wait);
89 if (rng->data_present)
90 present = rng->data_present(rng, wait);
95 return rng->data_read(rng, (u32 *)buffer);
100 static ssize_t rng_dev_read(struct file *filp, char __user *buf,
101 size_t size, loff_t *offp)
108 if (mutex_lock_interruptible(&rng_mutex)) {
119 bytes_read = rng_get_data(current_rng, rng_buffer,
121 !(filp->f_flags & O_NONBLOCK));
122 if (bytes_read < 0) {
126 data_avail = bytes_read;
130 if (filp->f_flags & O_NONBLOCK) {
141 if (copy_to_user(buf + ret, rng_buffer + data_avail,
151 mutex_unlock(&rng_mutex);
154 schedule_timeout_interruptible(1);
156 if (signal_pending(current)) {
164 mutex_unlock(&rng_mutex);
169 static const struct file_operations rng_chrdev_ops = {
170 .owner = THIS_MODULE,
171 .open = rng_dev_open,
172 .read = rng_dev_read,
175 static struct miscdevice rng_miscdev = {
176 .minor = RNG_MISCDEV_MINOR,
177 .name = RNG_MODULE_NAME,
179 .fops = &rng_chrdev_ops,
183 static ssize_t hwrng_attr_current_store(struct device *dev,
184 struct device_attribute *attr,
185 const char *buf, size_t len)
190 err = mutex_lock_interruptible(&rng_mutex);
194 list_for_each_entry(rng, &rng_list, list) {
195 if (strcmp(rng->name, buf) == 0) {
196 if (rng == current_rng) {
200 err = hwrng_init(rng);
203 hwrng_cleanup(current_rng);
209 mutex_unlock(&rng_mutex);
214 static ssize_t hwrng_attr_current_show(struct device *dev,
215 struct device_attribute *attr,
220 const char *name = "none";
222 err = mutex_lock_interruptible(&rng_mutex);
226 name = current_rng->name;
227 ret = snprintf(buf, PAGE_SIZE, "%s\n", name);
228 mutex_unlock(&rng_mutex);
233 static ssize_t hwrng_attr_available_show(struct device *dev,
234 struct device_attribute *attr,
241 err = mutex_lock_interruptible(&rng_mutex);
245 list_for_each_entry(rng, &rng_list, list) {
246 strncat(buf, rng->name, PAGE_SIZE - ret - 1);
247 ret += strlen(rng->name);
248 strncat(buf, " ", PAGE_SIZE - ret - 1);
251 strncat(buf, "\n", PAGE_SIZE - ret - 1);
253 mutex_unlock(&rng_mutex);
258 static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
259 hwrng_attr_current_show,
260 hwrng_attr_current_store);
261 static DEVICE_ATTR(rng_available, S_IRUGO,
262 hwrng_attr_available_show,
266 static void unregister_miscdev(void)
268 device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available);
269 device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
270 misc_deregister(&rng_miscdev);
273 static int register_miscdev(void)
277 err = misc_register(&rng_miscdev);
280 err = device_create_file(rng_miscdev.this_device,
281 &dev_attr_rng_current);
284 err = device_create_file(rng_miscdev.this_device,
285 &dev_attr_rng_available);
287 goto err_remove_current;
292 device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
294 misc_deregister(&rng_miscdev);
298 int hwrng_register(struct hwrng *rng)
300 int must_register_misc;
302 struct hwrng *old_rng, *tmp;
304 if (rng->name == NULL ||
305 (rng->data_read == NULL && rng->read == NULL))
308 mutex_lock(&rng_mutex);
310 /* Must not register two RNGs with the same name. */
312 list_for_each_entry(tmp, &rng_list, list) {
313 if (strcmp(tmp->name, rng->name) == 0)
317 must_register_misc = (current_rng == NULL);
318 old_rng = current_rng;
320 err = hwrng_init(rng);
326 if (must_register_misc) {
327 err = register_miscdev();
336 INIT_LIST_HEAD(&rng->list);
337 list_add_tail(&rng->list, &rng_list);
339 mutex_unlock(&rng_mutex);
343 EXPORT_SYMBOL_GPL(hwrng_register);
345 void hwrng_unregister(struct hwrng *rng)
349 mutex_lock(&rng_mutex);
351 list_del(&rng->list);
352 if (current_rng == rng) {
354 if (list_empty(&rng_list)) {
357 current_rng = list_entry(rng_list.prev, struct hwrng, list);
358 err = hwrng_init(current_rng);
363 if (list_empty(&rng_list))
364 unregister_miscdev();
366 mutex_unlock(&rng_mutex);
368 EXPORT_SYMBOL_GPL(hwrng_unregister);
371 MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
372 MODULE_LICENSE("GPL");