[PATCH] Generic hardware RNG support

From: Michael Buesch
Date: Tue Feb 28 2006 - 06:28:04 EST


Andrew, consider inclusion of the following patch into -mm
for further testing, please.

---

This patch adds support for generic Hardware Random Number Generator
drivers. This makes the usage of the bcm43xx internal RNG through
/dev/hwrandom possible.

A patch against bcm43xx for your testing pleasure can be found at:
ftp://ftp.bu3sch.de/misc/bcm43xx-d80211-hwrng.patch


diff -urNX 2.6.16-rc4-mm2/Documentation/dontdiff 2.6.16-rc4-mm2.orig/drivers/char/hw_random.c 2.6.16-rc4-mm2/drivers/char/hw_random.c
--- 2.6.16-rc4-mm2.orig/drivers/char/hw_random.c 2006-02-28 11:54:50.000000000 +0100
+++ 2.6.16-rc4-mm2/drivers/char/hw_random.c 2006-02-28 12:07:56.000000000 +0100
@@ -18,6 +18,9 @@
Copyright 2000,2001 Jeff Garzik <jgarzik@xxxxxxxxx>
Copyright 2000,2001 Philipp Rumpf <prumpf@xxxxxxxxxxxxxxxx>

+ Added generic RNG API
+ Copyright 2006 Michael Buesch <mbuesch@xxxxxxxxxx>
+
Please read Documentation/hw_random.txt for details on use.

----------------------------------------------------------
@@ -27,11 +30,12 @@
*/


+#include <linux/hw_random.h>
+#include <linux/pci.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/random.h>
@@ -49,13 +53,9 @@
#include <asm/uaccess.h>


-/*
- * core module and version information
- */
-#define RNG_VERSION "1.0.0"
-#define RNG_MODULE_NAME "hw_random"
-#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION
-#define PFX RNG_MODULE_NAME ": "
+#define RNG_MODULE_NAME "hw_random"
+#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver"
+#define PFX RNG_MODULE_NAME ": "


/*
@@ -83,36 +83,31 @@
static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
loff_t * offp);

-static int __init intel_init (struct pci_dev *dev);
-static void intel_cleanup(void);
-static unsigned int intel_data_present (void);
-static u32 intel_data_read (void);
-
-static int __init amd_init (struct pci_dev *dev);
-static void amd_cleanup(void);
-static unsigned int amd_data_present (void);
-static u32 amd_data_read (void);
+static int __init intel_init (struct hwrng *rng);
+static void intel_cleanup(struct hwrng *rng);
+static unsigned int intel_data_present (struct hwrng *rng);
+static u32 intel_data_read (struct hwrng *rng);
+
+static int __init amd_init (struct hwrng *rng);
+static void amd_cleanup(struct hwrng *rng);
+static unsigned int amd_data_present (struct hwrng *rng);
+static u32 amd_data_read (struct hwrng *rng);

#ifdef __i386__
-static int __init via_init(struct pci_dev *dev);
-static void via_cleanup(void);
-static unsigned int via_data_present (void);
-static u32 via_data_read (void);
+static int __init via_init(struct hwrng *rng);
+static void via_cleanup(struct hwrng *rng);
+static unsigned int via_data_present (struct hwrng *rng);
+static u32 via_data_read (struct hwrng *rng);
#endif

-static int __init geode_init(struct pci_dev *dev);
-static void geode_cleanup(void);
-static unsigned int geode_data_present (void);
-static u32 geode_data_read (void);
-
-struct rng_operations {
- int (*init) (struct pci_dev *dev);
- void (*cleanup) (void);
- unsigned int (*data_present) (void);
- u32 (*data_read) (void);
- unsigned int n_bytes; /* number of bytes per ->data_read */
-};
-static struct rng_operations *rng_ops;
+static int __init geode_init(struct hwrng *rng);
+static void geode_cleanup(struct hwrng *rng);
+static unsigned int geode_data_present (struct hwrng *rng);
+static u32 geode_data_read (struct hwrng *rng);
+
+static struct hwrng *current_rng;
+static LIST_HEAD(rng_list);
+static DEFINE_MUTEX(rng_mutex);

static struct file_operations rng_chrdev_ops = {
.owner = THIS_MODULE,
@@ -122,9 +117,9 @@


static struct miscdevice rng_miscdev = {
- RNG_MISCDEV_MINOR,
- RNG_MODULE_NAME,
- &rng_chrdev_ops,
+ .minor = RNG_MISCDEV_MINOR,
+ .name = RNG_MODULE_NAME,
+ .fops = &rng_chrdev_ops,
};

enum {
@@ -135,24 +130,41 @@
rng_hw_geode,
};

-static struct rng_operations rng_vendor_ops[] = {
- /* rng_hw_none */
- { },
-
- /* rng_hw_intel */
- { intel_init, intel_cleanup, intel_data_present,
- intel_data_read, 1 },
-
- /* rng_hw_amd */
- { amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 },
-
+static struct hwrng rng_vendor_ops[] = {
+ { /* rng_hw_none */
+ }, { /* rng_hw_intel */
+ .name = "intel",
+ .init = intel_init,
+ .cleanup = intel_cleanup,
+ .data_present = intel_data_present,
+ .data_read = intel_data_read,
+ .n_bytes = 1,
+ }, { /* rng_hw_amd */
+ .name = "amd",
+ .init = amd_init,
+ .cleanup = amd_cleanup,
+ .data_present = amd_data_present,
+ .data_read = amd_data_read,
+ .n_bytes = 4,
+ },
#ifdef __i386__
- /* rng_hw_via */
- { via_init, via_cleanup, via_data_present, via_data_read, 1 },
+ { /* rng_hw_via */
+ .name = "via",
+ .init = via_init,
+ .cleanup = via_cleanup,
+ .data_present = via_data_present,
+ .data_read = via_data_read,
+ .n_bytes = 1,
+ },
#endif
-
- /* rng_hw_geode */
- { geode_init, geode_cleanup, geode_data_present, geode_data_read, 4 }
+ { /* rng_hw_geode */
+ .name = "geode",
+ .init = geode_init,
+ .cleanup = geode_cleanup,
+ .data_present = geode_data_present,
+ .data_read = geode_data_read,
+ .n_bytes = 4,
+ },
};

/*
@@ -204,39 +216,39 @@
#define INTEL_RNG_ADDR 0xFFBC015F
#define INTEL_RNG_ADDR_LEN 3

-/* token to our ioremap'd RNG register area */
-static void __iomem *rng_mem;
-
-static inline u8 intel_hwstatus (void)
+static inline u8 intel_hwstatus (void __iomem *rng_mem)
{
assert (rng_mem != NULL);
return readb (rng_mem + INTEL_RNG_HW_STATUS);
}

-static inline u8 intel_hwstatus_set (u8 hw_status)
+static inline u8 intel_hwstatus_set (void __iomem *rng_mem, u8 hw_status)
{
assert (rng_mem != NULL);
writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS);
- return intel_hwstatus ();
+ return intel_hwstatus (rng_mem);
}

-static unsigned int intel_data_present(void)
+static unsigned int intel_data_present(struct hwrng *rng)
{
- assert (rng_mem != NULL);
+ void __iomem *rng_mem = (void __iomem *)rng->priv;

+ assert (rng_mem != NULL);
return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ?
1 : 0;
}

-static u32 intel_data_read(void)
+static u32 intel_data_read(struct hwrng *rng)
{
- assert (rng_mem != NULL);
+ void __iomem *rng_mem = (void __iomem *)rng->priv;

+ assert (rng_mem != NULL);
return readb (rng_mem + INTEL_RNG_DATA);
}

-static int __init intel_init (struct pci_dev *dev)
+static int __init intel_init(struct hwrng *rng)
{
+ void __iomem *rng_mem;
int rc;
u8 hw_status;

@@ -248,9 +260,10 @@
rc = -EBUSY;
goto err_out;
}
+ rng->priv = (unsigned long)rng_mem;

/* Check for Intel 82802 */
- hw_status = intel_hwstatus ();
+ hw_status = intel_hwstatus (rng_mem);
if ((hw_status & INTEL_RNG_PRESENT) == 0) {
printk (KERN_ERR PFX "RNG not detected\n");
rc = -ENODEV;
@@ -259,7 +272,7 @@

/* turn RNG h/w on, if it's off */
if ((hw_status & INTEL_RNG_ENABLED) == 0)
- hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED);
+ hw_status = intel_hwstatus_set (rng_mem, hw_status | INTEL_RNG_ENABLED);
if ((hw_status & INTEL_RNG_ENABLED) == 0) {
printk (KERN_ERR PFX "cannot enable RNG, aborting\n");
rc = -EIO;
@@ -271,23 +284,22 @@

err_out_free_map:
iounmap (rng_mem);
- rng_mem = NULL;
err_out:
DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}

-static void intel_cleanup(void)
+static void intel_cleanup(struct hwrng *rng)
{
+ void __iomem *rng_mem = (void __iomem *)rng->priv;
u8 hw_status;

- hw_status = intel_hwstatus ();
+ hw_status = intel_hwstatus (rng_mem);
if (hw_status & INTEL_RNG_ENABLED)
- intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED);
+ intel_hwstatus_set (rng_mem, hw_status & ~INTEL_RNG_ENABLED);
else
printk(KERN_WARNING PFX "unusual: RNG already disabled\n");
iounmap(rng_mem);
- rng_mem = NULL;
}

/***********************************************************************
@@ -296,22 +308,25 @@
*
*/

-static u32 pmbase; /* PMxx I/O base */
-static struct pci_dev *amd_dev;
-
-static unsigned int amd_data_present (void)
+static unsigned int amd_data_present (struct hwrng *rng)
{
+ u32 pmbase = (u32)rng->priv;
+
return inl(pmbase + 0xF4) & 1;
}


-static u32 amd_data_read (void)
+static u32 amd_data_read (struct hwrng *rng)
{
+ u32 pmbase = (u32)rng->priv;
+
return inl(pmbase + 0xF0);
}

-static int __init amd_init (struct pci_dev *dev)
+static int __init amd_init(struct hwrng *rng)
{
+ u32 pmbase;
+ struct pci_dev *dev = rng->dev;
int rc;
u8 rnen;

@@ -327,6 +342,7 @@
rc = -EIO;
goto err_out;
}
+ rng->priv = (unsigned long)pmbase;

pci_read_config_byte(dev, 0x40, &rnen);
rnen |= (1 << 7); /* RNG on */
@@ -339,8 +355,6 @@
pr_info( PFX "AMD768 system management I/O registers at 0x%X.\n",
pmbase);

- amd_dev = dev;
-
DPRINTK ("EXIT, returning 0\n");
return 0;

@@ -349,13 +363,13 @@
return rc;
}

-static void amd_cleanup(void)
+static void amd_cleanup(struct hwrng *rng)
{
u8 rnen;

- pci_read_config_byte(amd_dev, 0x40, &rnen);
+ pci_read_config_byte(rng->dev, 0x40, &rnen);
rnen &= ~(1 << 7); /* RNG off */
- pci_write_config_byte(amd_dev, 0x40, rnen);
+ pci_write_config_byte(rng->dev, 0x40, rnen);

/* FIXME: twiddle pmio, also? */
}
@@ -384,8 +398,6 @@
VIA_RNG_CHUNK_1_MASK = 0xFF,
};

-static u32 via_rng_datum;
-
/*
* Investigate using the 'rep' prefix to obtain 32 bits of random data
* in one insn. The upside is potentially better performance. The
@@ -411,9 +423,10 @@
return eax_out;
}

-static unsigned int via_data_present(void)
+static unsigned int via_data_present(struct hwrng *rng)
{
u32 bytes_out;
+ u32 *via_rng_datum = (u32 *)(&rng->priv);

/* We choose the recommended 1-byte-per-instruction RNG rate,
* for greater randomness at the expense of speed. Larger
@@ -427,20 +440,23 @@
* A copy of MSR_VIA_RNG is placed in eax_out when xstore
* completes.
*/
- via_rng_datum = 0; /* paranoia, not really necessary */
- bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK;
+
+ *via_rng_datum = 0; /* paranoia, not really necessary */
+ bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK;
if (bytes_out == 0)
return 0;

return 1;
}

-static u32 via_data_read(void)
+static u32 via_data_read(struct hwrng *rng)
{
+ u32 via_rng_datum = (u32)rng->priv;
+
return via_rng_datum;
}

-static int __init via_init(struct pci_dev *dev)
+static int __init via_init(struct hwrng *rng)
{
u32 lo, hi, old_lo;

@@ -472,7 +488,7 @@
return 0;
}

-static void via_cleanup(void)
+static void via_cleanup(struct hwrng *rng)
{
/* do nothing */
}
@@ -484,13 +500,12 @@
*
*/

-static void __iomem *geode_rng_base = NULL;
-
#define GEODE_RNG_DATA_REG 0x50
#define GEODE_RNG_STATUS_REG 0x54

-static u32 geode_data_read(void)
+static u32 geode_data_read(struct hwrng *rng)
{
+ void __iomem *geode_rng_base = (void __iomem *)rng->priv;
u32 val;

assert(geode_rng_base != NULL);
@@ -498,8 +513,9 @@
return val;
}

-static unsigned int geode_data_present(void)
+static unsigned int geode_data_present(struct hwrng *rng)
{
+ void __iomem *geode_rng_base = (void __iomem *)rng->priv;
u32 val;

assert(geode_rng_base != NULL);
@@ -507,14 +523,18 @@
return val;
}

-static void geode_cleanup(void)
+static void geode_cleanup(struct hwrng *rng)
{
+ void __iomem *geode_rng_base = (void __iomem *)rng->priv;
+
iounmap(geode_rng_base);
geode_rng_base = NULL;
}

-static int geode_init(struct pci_dev *dev)
+static int geode_init(struct hwrng *rng)
{
+ void __iomem *geode_rng_base;
+ struct pci_dev *dev = rng->dev;
unsigned long rng_base = pci_resource_start(dev, 0);

if (rng_base == 0)
@@ -526,6 +546,7 @@
printk(KERN_ERR PFX "Cannot ioremap RNG memory\n");
return -EBUSY;
}
+ rng->priv = (unsigned long)geode_rng_base;

return 0;
}
@@ -543,7 +564,6 @@
return -EINVAL;
if (filp->f_mode & FMODE_WRITE)
return -EINVAL;
-
return 0;
}

@@ -551,21 +571,26 @@
static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
loff_t * offp)
{
- static DEFINE_SPINLOCK(rng_lock);
unsigned int have_data;
u32 data = 0;
ssize_t ret = 0;
+ int err;

while (size) {
- spin_lock(&rng_lock);
-
+ err = mutex_lock_interruptible(&rng_mutex);
+ if (err)
+ return err;
+ if (!current_rng) {
+ mutex_unlock(&rng_mutex);
+ return -ENODEV;
+ }
have_data = 0;
- if (rng_ops->data_present()) {
- data = rng_ops->data_read();
- have_data = rng_ops->n_bytes;
+ if (current_rng->data_present == NULL ||
+ current_rng->data_present(current_rng)) {
+ data = current_rng->data_read(current_rng);
+ have_data = current_rng->n_bytes;
}
-
- spin_unlock (&rng_lock);
+ mutex_unlock(&rng_mutex);

while (have_data && size) {
if (put_user((u8)data, buf++)) {
@@ -593,38 +618,186 @@
}


+static ssize_t hwrng_attr_current_store(struct class_device *class,
+ const char *buf, size_t len)
+{
+ int err = -ENODEV;
+ struct hwrng *rng;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ err = mutex_lock_interruptible(&rng_mutex);
+ if (err)
+ return err;
+ err = -ENODEV;
+ list_for_each_entry(rng, &rng_list, list) {
+ if (strncmp(rng->name, buf, len) == 0) {
+ if (rng->init) {
+ err = rng->init(rng);
+ if (err)
+ break;
+ }
+ if (current_rng && current_rng->cleanup)
+ current_rng->cleanup(current_rng);
+ current_rng = rng;
+ err = 0;
+ break;
+ }
+ }
+ mutex_unlock(&rng_mutex);

-/*
- * rng_init_one - look for and attempt to init a single RNG
- */
-static int __init rng_init_one (struct pci_dev *dev)
+ return err ? err : len;
+}
+
+static ssize_t hwrng_attr_current_show(struct class_device *class,
+ char *buf)
{
- int rc;
+ int err;
+ ssize_t ret;
+ const char *name;

- DPRINTK ("ENTER\n");
+ err = mutex_lock_interruptible(&rng_mutex);
+ if (err)
+ return err;
+ if (current_rng)
+ name = current_rng->name;
+ else
+ name = "none";
+ ret = sprintf(buf, "%s\n", name);
+ mutex_unlock(&rng_mutex);

- assert(rng_ops != NULL);
+ return ret;
+}

- rc = rng_ops->init(dev);
- if (rc)
- goto err_out;
+static ssize_t hwrng_attr_available_show(struct class_device *class,
+ char *buf)
+{
+ int err;
+ ssize_t ret = 0;
+ struct hwrng *rng;

- rc = misc_register (&rng_miscdev);
- if (rc) {
- printk (KERN_ERR PFX "misc device register failed\n");
- goto err_out_cleanup_hw;
+ err = mutex_lock_interruptible(&rng_mutex);
+ if (err)
+ return err;
+ buf[0] = '\0';
+ list_for_each_entry(rng, &rng_list, list) {
+ ret += strlen(rng->name);
+ strcat(buf, rng->name);
+ ret += 1;
+ strcat(buf, " ");
}
+ strcat(buf, "\n");
+ ret += 1;
+ mutex_unlock(&rng_mutex);

- DPRINTK ("EXIT, returning 0\n");
- return 0;
+ return ret;
+}

-err_out_cleanup_hw:
- rng_ops->cleanup();
-err_out:
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
+static CLASS_DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
+ hwrng_attr_current_show,
+ hwrng_attr_current_store);
+static CLASS_DEVICE_ATTR(rng_available, S_IRUGO,
+ hwrng_attr_available_show,
+ NULL);
+
+
+static void unregister_miscdev(void)
+{
+ class_device_remove_file(rng_miscdev.class,
+ &class_device_attr_rng_available);
+ class_device_remove_file(rng_miscdev.class,
+ &class_device_attr_rng_current);
+ misc_deregister(&rng_miscdev);
+}
+
+static int register_miscdev(void)
+{
+ int err;
+
+ err = misc_register(&rng_miscdev);
+ if (err)
+ goto out;
+ err = class_device_create_file(rng_miscdev.class,
+ &class_device_attr_rng_current);
+ if (err)
+ goto err_misc_dereg;
+ err = class_device_create_file(rng_miscdev.class,
+ &class_device_attr_rng_available);
+ if (err)
+ goto err_remove_current;
+out:
+ return err;
+
+err_remove_current:
+ class_device_remove_file(rng_miscdev.class,
+ &class_device_attr_rng_current);
+err_misc_dereg:
+ misc_deregister(&rng_miscdev);
+ goto out;
+}
+
+int hwrng_register(struct hwrng *rng)
+{
+ int must_register_misc;
+ int err;
+ struct hwrng *old_current;
+
+ if (rng->name == NULL)
+ return -EINVAL;
+ if (rng->data_read == NULL)
+ return -EINVAL;
+ if (rng->n_bytes < 1 || rng->n_bytes > sizeof(u32))
+ return -EINVAL;
+
+ mutex_lock(&rng_mutex);
+ must_register_misc = (current_rng == NULL);
+ old_current = current_rng;
+ if (!current_rng) {
+ if (rng->init) {
+ err = rng->init(rng);
+ if (err) {
+ mutex_unlock(&rng_mutex);
+ return err;
+ }
+ }
+ current_rng = rng;
+ }
+ INIT_LIST_HEAD(&rng->list);
+ list_add_tail(&rng->list, &rng_list);
+ err = 0;
+ if (must_register_misc) {
+ err = register_miscdev();
+ if (err) {
+ if (rng->cleanup)
+ rng->cleanup(rng);
+ list_del(&rng->list);
+ current_rng = old_current;
+ }
+ }
+
+ mutex_unlock(&rng_mutex);
+
+ return err;
}
+EXPORT_SYMBOL_GPL(hwrng_register);

+void hwrng_unregister(struct hwrng *rng)
+{
+ mutex_lock(&rng_mutex);
+ list_del(&rng->list);
+ if (current_rng == rng) {
+ if (rng->cleanup)
+ rng->cleanup(rng);
+ if (list_empty(&rng_list))
+ current_rng = NULL;
+ else
+ current_rng = list_entry(rng_list.prev, struct hwrng, list);
+ }
+ if (list_empty(&rng_list))
+ unregister_miscdev();
+ mutex_unlock(&rng_mutex);
+}
+EXPORT_SYMBOL_GPL(hwrng_unregister);


MODULE_AUTHOR("The Linux Kernel team");
@@ -637,7 +810,7 @@
*/
static int __init rng_init (void)
{
- int rc;
+ int err;
struct pci_dev *pdev = NULL;
const struct pci_device_id *ent;

@@ -647,28 +820,30 @@
for_each_pci_dev(pdev) {
ent = pci_match_id(rng_pci_tbl, pdev);
if (ent) {
- rng_ops = &rng_vendor_ops[ent->driver_data];
- goto match;
+ err = hwrng_register(&rng_vendor_ops[ent->driver_data]);
+ if (err) {
+ printk(KERN_ERR PFX "Could not register Intel, "
+ "AMD or Geode RNG\n");
+ return err;
+ }
+ goto out;
}
}

#ifdef __i386__
/* Probe for VIA RNG */
if (cpu_has_xstore) {
- rng_ops = &rng_vendor_ops[rng_hw_via];
- pdev = NULL;
- goto match;
+ err = hwrng_register(&rng_vendor_ops[rng_hw_via]);
+ if (err) {
+ printk(KERN_ERR PFX "Could not register VIA RNG\n");
+ return err;
+ }
+ goto out;
}
#endif

- DPRINTK ("EXIT, returning -ENODEV\n");
- return -ENODEV;
-
-match:
- rc = rng_init_one (pdev);
- if (rc)
- return rc;
-
+ DPRINTK ("no device found\n");
+out:
pr_info( RNG_DRIVER_NAME " loaded\n");

DPRINTK ("EXIT, returning 0\n");
@@ -683,10 +858,8 @@
{
DPRINTK ("ENTER\n");

- misc_deregister (&rng_miscdev);
-
- if (rng_ops->cleanup)
- rng_ops->cleanup();
+ if (current_rng)
+ hwrng_unregister(current_rng);

DPRINTK ("EXIT\n");
}
diff -urNX 2.6.16-rc4-mm2/Documentation/dontdiff 2.6.16-rc4-mm2.orig/drivers/char/Kconfig 2.6.16-rc4-mm2/drivers/char/Kconfig
--- 2.6.16-rc4-mm2.orig/drivers/char/Kconfig 2006-02-28 11:54:48.000000000 +0100
+++ 2.6.16-rc4-mm2/drivers/char/Kconfig 2006-02-28 11:55:34.000000000 +0100
@@ -653,8 +653,8 @@
If you're not sure, say N.

config HW_RANDOM
- tristate "Intel/AMD/VIA HW Random Number Generator support"
- depends on (X86 || IA64) && PCI
+ tristate "Intel/AMD/VIA/Generic HW Random Number Generator support"
+ depends on PCI
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on Intel i8xx-based motherboards,
diff -urNX 2.6.16-rc4-mm2/Documentation/dontdiff 2.6.16-rc4-mm2.orig/include/linux/hw_random.h 2.6.16-rc4-mm2/include/linux/hw_random.h
--- 2.6.16-rc4-mm2.orig/include/linux/hw_random.h 1970-01-01 01:00:00.000000000 +0100
+++ 2.6.16-rc4-mm2/include/linux/hw_random.h 2006-02-28 11:55:34.000000000 +0100
@@ -0,0 +1,48 @@
+/*
+ Hardware Random Number Generator
+
+ Please read Documentation/hw_random.txt for details on use.
+
+ ----------------------------------------------------------
+ This software may be used and distributed according to the terms
+ of the GNU General Public License, incorporated herein by reference.
+
+ */
+
+#ifndef LINUX_HWRANDOM_H_
+#define LINUX_HWRANDOM_H_
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct pci_dev;
+
+struct hwrng {
+ /** Unique name. */
+ const char *name;
+ /** Pointer to the PCI device (can be NULL). */
+ struct pci_dev *dev;
+
+ /** Initialization callback. */
+ int (*init) (struct hwrng *rng);
+ /** Cleanup callback. */
+ void (*cleanup) (struct hwrng *rng);
+ /** Is the RNG able to provide data now? */
+ unsigned int (*data_present) (struct hwrng *rng);
+ /** Read data from the RNG device. */
+ u32 (*data_read) (struct hwrng *rng);
+ /** Number of bytes read per data_read() call.
+ * This must be > 0 and < sizeof(u32).
+ */
+ unsigned int n_bytes;
+ /** Private data, for use by the RNG driver. */
+ unsigned long priv;
+
+ /* internal. */
+ struct list_head list;
+};
+
+extern int hwrng_register(struct hwrng *rng);
+extern void hwrng_unregister(struct hwrng *rng);
+
+#endif /* LINUX_HWRANDOM_H_ */

--
Greetings Michael.

Attachment: hw_random-generic_2.6.16-rc4-mm2.patch.bz2
Description: BZip2 compressed data

Attachment: pgp00000.pgp
Description: PGP signature