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)
8 (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
12 Hardware driver for the AMD 768 Random Number Generator (RNG)
13 (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
17 Hardware driver for Intel i810 Random Number Generator (RNG)
18 Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
19 Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
22 Copyright 2006 Michael Buesch <m@bues.ch>
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/miscdevice.h>
41 #include <linux/delay.h>
42 #include <linux/slab.h>
43 #include <asm/uaccess.h>
46 #define RNG_MODULE_NAME "hw_random"
47 #define PFX RNG_MODULE_NAME ": "
48 #define RNG_MISCDEV_MINOR 183 /* official */
51 static struct hwrng *current_rng;
52 static LIST_HEAD(rng_list);
53 static DEFINE_MUTEX(rng_mutex);
54 static int data_avail;
55 static u8 *rng_buffer;
57 static size_t rng_buffer_size(void)
59 return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES;
62 static inline int hwrng_init(struct hwrng *rng)
66 return rng->init(rng);
69 static inline void hwrng_cleanup(struct hwrng *rng)
71 if (rng && rng->cleanup)
75 static int rng_dev_open(struct inode *inode, struct file *filp)
77 /* enforce read-only access to this chrdev */
78 if ((filp->f_mode & FMODE_READ) == 0)
80 if (filp->f_mode & FMODE_WRITE)
85 static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
90 return rng->read(rng, (void *)buffer, size, wait);
92 if (rng->data_present)
93 present = rng->data_present(rng, wait);
98 return rng->data_read(rng, (u32 *)buffer);
103 static ssize_t rng_dev_read(struct file *filp, char __user *buf,
104 size_t size, loff_t *offp)
111 if (mutex_lock_interruptible(&rng_mutex)) {
122 bytes_read = rng_get_data(current_rng, rng_buffer,
124 !(filp->f_flags & O_NONBLOCK));
125 if (bytes_read < 0) {
129 data_avail = bytes_read;
133 if (filp->f_flags & O_NONBLOCK) {
144 if (copy_to_user(buf + ret, rng_buffer + data_avail,
154 mutex_unlock(&rng_mutex);
157 schedule_timeout_interruptible(1);
159 if (signal_pending(current)) {
167 mutex_unlock(&rng_mutex);
172 static const struct file_operations rng_chrdev_ops = {
173 .owner = THIS_MODULE,
174 .open = rng_dev_open,
175 .read = rng_dev_read,
176 .llseek = noop_llseek,
179 static struct miscdevice rng_miscdev = {
180 .minor = RNG_MISCDEV_MINOR,
181 .name = RNG_MODULE_NAME,
183 .fops = &rng_chrdev_ops,
187 static ssize_t hwrng_attr_current_store(struct device *dev,
188 struct device_attribute *attr,
189 const char *buf, size_t len)
194 err = mutex_lock_interruptible(&rng_mutex);
198 list_for_each_entry(rng, &rng_list, list) {
199 if (strcmp(rng->name, buf) == 0) {
200 if (rng == current_rng) {
204 err = hwrng_init(rng);
207 hwrng_cleanup(current_rng);
213 mutex_unlock(&rng_mutex);
218 static ssize_t hwrng_attr_current_show(struct device *dev,
219 struct device_attribute *attr,
224 const char *name = "none";
226 err = mutex_lock_interruptible(&rng_mutex);
230 name = current_rng->name;
231 ret = snprintf(buf, PAGE_SIZE, "%s\n", name);
232 mutex_unlock(&rng_mutex);
237 static ssize_t hwrng_attr_available_show(struct device *dev,
238 struct device_attribute *attr,
245 err = mutex_lock_interruptible(&rng_mutex);
249 list_for_each_entry(rng, &rng_list, list) {
250 strncat(buf, rng->name, PAGE_SIZE - ret - 1);
251 ret += strlen(rng->name);
252 strncat(buf, " ", PAGE_SIZE - ret - 1);
255 strncat(buf, "\n", PAGE_SIZE - ret - 1);
257 mutex_unlock(&rng_mutex);
262 static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
263 hwrng_attr_current_show,
264 hwrng_attr_current_store);
265 static DEVICE_ATTR(rng_available, S_IRUGO,
266 hwrng_attr_available_show,
270 static void unregister_miscdev(void)
272 device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available);
273 device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
274 misc_deregister(&rng_miscdev);
277 static int register_miscdev(void)
281 err = misc_register(&rng_miscdev);
284 err = device_create_file(rng_miscdev.this_device,
285 &dev_attr_rng_current);
288 err = device_create_file(rng_miscdev.this_device,
289 &dev_attr_rng_available);
291 goto err_remove_current;
296 device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
298 misc_deregister(&rng_miscdev);
302 int hwrng_register(struct hwrng *rng)
304 int must_register_misc;
306 struct hwrng *old_rng, *tmp;
308 if (rng->name == NULL ||
309 (rng->data_read == NULL && rng->read == NULL))
312 mutex_lock(&rng_mutex);
314 /* kmalloc makes this safe for virt_to_page() in virtio_rng.c */
317 rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL);
322 /* Must not register two RNGs with the same name. */
324 list_for_each_entry(tmp, &rng_list, list) {
325 if (strcmp(tmp->name, rng->name) == 0)
329 must_register_misc = (current_rng == NULL);
330 old_rng = current_rng;
332 err = hwrng_init(rng);
338 if (must_register_misc) {
339 err = register_miscdev();
348 INIT_LIST_HEAD(&rng->list);
349 list_add_tail(&rng->list, &rng_list);
351 mutex_unlock(&rng_mutex);
355 EXPORT_SYMBOL_GPL(hwrng_register);
357 void hwrng_unregister(struct hwrng *rng)
361 mutex_lock(&rng_mutex);
363 list_del(&rng->list);
364 if (current_rng == rng) {
366 if (list_empty(&rng_list)) {
369 current_rng = list_entry(rng_list.prev, struct hwrng, list);
370 err = hwrng_init(current_rng);
375 if (list_empty(&rng_list))
376 unregister_miscdev();
378 mutex_unlock(&rng_mutex);
380 EXPORT_SYMBOL_GPL(hwrng_unregister);
382 static void __exit hwrng_exit(void)
384 mutex_lock(&rng_mutex);
387 mutex_unlock(&rng_mutex);
390 module_exit(hwrng_exit);
392 MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
393 MODULE_LICENSE("GPL");