i810_rng.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
- /*
- Hardware driver for Intel i810 Random Number Generator (RNG)
- Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
- Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
- Driver Web site: http://sourceforge.net/projects/gkernel/
- Please read Documentation/i810_rng.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.
- */
- #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>
- #include <linux/miscdevice.h>
- #include <linux/smp_lock.h>
- #include <linux/mm.h>
- #include <asm/io.h>
- #include <asm/uaccess.h>
- /*
- * core module and version information
- */
- #define RNG_VERSION "0.9.6"
- #define RNG_MODULE_NAME "i810_rng"
- #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION
- #define PFX RNG_MODULE_NAME ": "
- /*
- * debugging macros
- */
- #undef RNG_DEBUG /* define to enable copious debugging info */
- #ifdef RNG_DEBUG
- /* note: prints function name for you */
- #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
- #else
- #define DPRINTK(fmt, args...)
- #endif
- #undef RNG_NDEBUG /* define to disable lightweight runtime checks */
- #ifdef RNG_NDEBUG
- #define assert(expr)
- #else
- #define assert(expr)
- if(!(expr)) {
- printk( "Assertion failed! %s,%s,%s,line=%dn",
- #expr,__FILE__,__FUNCTION__,__LINE__);
- }
- #endif
- /*
- * RNG registers (offsets from rng_mem)
- */
- #define RNG_HW_STATUS 0
- #define RNG_PRESENT 0x40
- #define RNG_ENABLED 0x01
- #define RNG_STATUS 1
- #define RNG_DATA_PRESENT 0x01
- #define RNG_DATA 2
- /*
- * Magic address at which Intel PCI bridges locate the RNG
- */
- #define RNG_ADDR 0xFFBC015F
- #define RNG_ADDR_LEN 3
- #define RNG_MISCDEV_MINOR 183 /* official */
- /*
- * various RNG status variables. they are globals
- * as we only support a single RNG device
- */
- static void *rng_mem; /* token to our ioremap'd RNG register area */
- static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */
- /*
- * inlined helper functions for accessing RNG registers
- */
- static inline u8 rng_hwstatus (void)
- {
- assert (rng_mem != NULL);
- return readb (rng_mem + RNG_HW_STATUS);
- }
- static inline u8 rng_hwstatus_set (u8 hw_status)
- {
- assert (rng_mem != NULL);
- writeb (hw_status, rng_mem + RNG_HW_STATUS);
- return rng_hwstatus ();
- }
- static inline int rng_data_present (void)
- {
- assert (rng_mem != NULL);
- return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0;
- }
- static inline int rng_data_read (void)
- {
- assert (rng_mem != NULL);
- return readb (rng_mem + RNG_DATA);
- }
- /*
- * rng_enable - enable the RNG hardware
- */
- static int rng_enable (void)
- {
- int rc = 0;
- u8 hw_status, new_status;
- DPRINTK ("ENTERn");
- hw_status = rng_hwstatus ();
- if ((hw_status & RNG_ENABLED) == 0) {
- new_status = rng_hwstatus_set (hw_status | RNG_ENABLED);
- if (new_status & RNG_ENABLED)
- printk (KERN_INFO PFX "RNG h/w enabledn");
- else {
- printk (KERN_ERR PFX "Unable to enable the RNGn");
- rc = -EIO;
- }
- }
- DPRINTK ("EXIT, returning %dn", rc);
- return rc;
- }
- /*
- * rng_disable - disable the RNG hardware
- */
- static void rng_disable(void)
- {
- u8 hw_status, new_status;
- DPRINTK ("ENTERn");
- hw_status = rng_hwstatus ();
- if (hw_status & RNG_ENABLED) {
- new_status = rng_hwstatus_set (hw_status & ~RNG_ENABLED);
-
- if ((new_status & RNG_ENABLED) == 0)
- printk (KERN_INFO PFX "RNG h/w disabledn");
- else {
- printk (KERN_ERR PFX "Unable to disable the RNGn");
- }
- }
- DPRINTK ("EXITn");
- }
- static int rng_dev_open (struct inode *inode, struct file *filp)
- {
- int rc;
- if ((filp->f_mode & FMODE_READ) == 0)
- return -EINVAL;
- if (filp->f_mode & FMODE_WRITE)
- return -EINVAL;
- /* wait for device to become free */
- if (filp->f_flags & O_NONBLOCK) {
- if (down_trylock (&rng_open_sem))
- return -EAGAIN;
- } else {
- if (down_interruptible (&rng_open_sem))
- return -ERESTARTSYS;
- }
- rc = rng_enable ();
- if (rc) {
- up (&rng_open_sem);
- return rc;
- }
- return 0;
- }
- static int rng_dev_release (struct inode *inode, struct file *filp)
- {
- rng_disable ();
- up (&rng_open_sem);
- return 0;
- }
- static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size,
- loff_t * offp)
- {
- static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED;
- int have_data;
- u8 data = 0;
- ssize_t ret = 0;
- while (size) {
- spin_lock (&rng_lock);
- have_data = 0;
- if (rng_data_present ()) {
- data = rng_data_read ();
- have_data = 1;
- }
- spin_unlock (&rng_lock);
- if (have_data) {
- if (put_user (data, buf++)) {
- ret = ret ? : -EFAULT;
- break;
- }
- size--;
- ret++;
- }
- if (filp->f_flags & O_NONBLOCK)
- return ret ? : -EAGAIN;
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
- if (signal_pending (current))
- return ret ? : -ERESTARTSYS;
- }
- return ret;
- }
- static struct file_operations rng_chrdev_ops = {
- owner: THIS_MODULE,
- open: rng_dev_open,
- release: rng_dev_release,
- read: rng_dev_read,
- };
- static struct miscdevice rng_miscdev = {
- RNG_MISCDEV_MINOR,
- RNG_MODULE_NAME,
- &rng_chrdev_ops,
- };
- /*
- * rng_init_one - look for and attempt to init a single RNG
- */
- static int __init rng_init_one (struct pci_dev *dev)
- {
- int rc;
- u8 hw_status;
- DPRINTK ("ENTERn");
- rc = misc_register (&rng_miscdev);
- if (rc) {
- printk (KERN_ERR PFX "cannot register misc devicen");
- DPRINTK ("EXIT, returning %dn", rc);
- goto err_out;
- }
- rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN);
- if (rng_mem == NULL) {
- printk (KERN_ERR PFX "cannot ioremap RNG Memoryn");
- DPRINTK ("EXIT, returning -EBUSYn");
- rc = -EBUSY;
- goto err_out_free_miscdev;
- }
- /* Check for Intel 82802 */
- hw_status = rng_hwstatus ();
- if ((hw_status & RNG_PRESENT) == 0) {
- printk (KERN_ERR PFX "RNG not detectedn");
- DPRINTK ("EXIT, returning -ENODEVn");
- rc = -ENODEV;
- goto err_out_free_map;
- }
- /* turn RNG h/w off, if it's on */
- if (hw_status & RNG_ENABLED)
- hw_status = rng_hwstatus_set (hw_status & ~RNG_ENABLED);
- if (hw_status & RNG_ENABLED) {
- printk (KERN_ERR PFX "cannot disable RNG, abortingn");
- goto err_out_free_map;
- }
- DPRINTK ("EXIT, returning 0n");
- return 0;
- err_out_free_map:
- iounmap (rng_mem);
- err_out_free_miscdev:
- misc_deregister (&rng_miscdev);
- err_out:
- return rc;
- }
- /*
- * Data for PCI driver interface
- *
- * This data only exists for exporting the supported
- * PCI ids via MODULE_DEVICE_TABLE. We do not actually
- * register a pci_driver, because someone else might one day
- * want to register another driver on the same PCI id.
- */
- static struct pci_device_id rng_pci_tbl[] __initdata = {
- { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x8086, 0x1130, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, },
- };
- MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
- MODULE_AUTHOR("Jeff Garzik, Philipp Rumpf, Matt Sottek");
- MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver");
- MODULE_LICENSE("GPL");
- /*
- * rng_init - initialize RNG module
- */
- static int __init rng_init (void)
- {
- int rc;
- struct pci_dev *pdev;
- DPRINTK ("ENTERn");
- init_MUTEX (&rng_open_sem);
- pci_for_each_dev(pdev) {
- if (pci_match_device (rng_pci_tbl, pdev) != NULL)
- goto match;
- }
- DPRINTK ("EXIT, returning -ENODEVn");
- return -ENODEV;
- match:
- rc = rng_init_one (pdev);
- if (rc)
- return rc;
- printk (KERN_INFO RNG_DRIVER_NAME " loadedn");
- DPRINTK ("EXIT, returning 0n");
- return 0;
- }
- /*
- * rng_init - shutdown RNG module
- */
- static void __exit rng_cleanup (void)
- {
- DPRINTK ("ENTERn");
- misc_deregister (&rng_miscdev);
- iounmap (rng_mem);
- DPRINTK ("EXITn");
- }
- module_init (rng_init);
- module_exit (rng_cleanup);