i810_rng.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2. Hardware driver for Intel i810 Random Number Generator (RNG)
  3. Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
  4. Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
  5. Driver Web site:  http://sourceforge.net/projects/gkernel/
  6. Please read Documentation/i810_rng.txt for details on use.
  7. ----------------------------------------------------------
  8. This software may be used and distributed according to the terms
  9.         of the GNU General Public License, incorporated herein by reference.
  10.  */
  11. #include <linux/module.h>
  12. #include <linux/kernel.h>
  13. #include <linux/fs.h>
  14. #include <linux/init.h>
  15. #include <linux/pci.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/spinlock.h>
  18. #include <linux/random.h>
  19. #include <linux/miscdevice.h>
  20. #include <linux/smp_lock.h>
  21. #include <linux/mm.h>
  22. #include <asm/io.h>
  23. #include <asm/uaccess.h>
  24. /*
  25.  * core module and version information
  26.  */
  27. #define RNG_VERSION "0.9.6"
  28. #define RNG_MODULE_NAME "i810_rng"
  29. #define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
  30. #define PFX RNG_MODULE_NAME ": "
  31. /*
  32.  * debugging macros
  33.  */
  34. #undef RNG_DEBUG /* define to enable copious debugging info */
  35. #ifdef RNG_DEBUG
  36. /* note: prints function name for you */
  37. #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
  38. #else
  39. #define DPRINTK(fmt, args...)
  40. #endif
  41. #undef RNG_NDEBUG        /* define to disable lightweight runtime checks */
  42. #ifdef RNG_NDEBUG
  43. #define assert(expr)
  44. #else
  45. #define assert(expr) 
  46.         if(!(expr)) {                                   
  47.         printk( "Assertion failed! %s,%s,%s,line=%dn", 
  48.         #expr,__FILE__,__FUNCTION__,__LINE__);          
  49.         }
  50. #endif
  51. /*
  52.  * RNG registers (offsets from rng_mem)
  53.  */
  54. #define RNG_HW_STATUS 0
  55. #define RNG_PRESENT 0x40
  56. #define RNG_ENABLED 0x01
  57. #define RNG_STATUS 1
  58. #define RNG_DATA_PRESENT 0x01
  59. #define RNG_DATA 2
  60. /*
  61.  * Magic address at which Intel PCI bridges locate the RNG
  62.  */
  63. #define RNG_ADDR 0xFFBC015F
  64. #define RNG_ADDR_LEN 3
  65. #define RNG_MISCDEV_MINOR 183 /* official */
  66. /*
  67.  * various RNG status variables.  they are globals
  68.  * as we only support a single RNG device
  69.  */
  70. static void *rng_mem; /* token to our ioremap'd RNG register area */
  71. static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */
  72. /*
  73.  * inlined helper functions for accessing RNG registers
  74.  */
  75. static inline u8 rng_hwstatus (void)
  76. {
  77. assert (rng_mem != NULL);
  78. return readb (rng_mem + RNG_HW_STATUS);
  79. }
  80. static inline u8 rng_hwstatus_set (u8 hw_status)
  81. {
  82. assert (rng_mem != NULL);
  83. writeb (hw_status, rng_mem + RNG_HW_STATUS);
  84. return rng_hwstatus ();
  85. }
  86. static inline int rng_data_present (void)
  87. {
  88. assert (rng_mem != NULL);
  89. return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0;
  90. }
  91. static inline int rng_data_read (void)
  92. {
  93. assert (rng_mem != NULL);
  94. return readb (rng_mem + RNG_DATA);
  95. }
  96. /*
  97.  * rng_enable - enable the RNG hardware
  98.  */
  99. static int rng_enable (void)
  100. {
  101. int rc = 0;
  102. u8 hw_status, new_status;
  103. DPRINTK ("ENTERn");
  104. hw_status = rng_hwstatus ();
  105. if ((hw_status & RNG_ENABLED) == 0) {
  106. new_status = rng_hwstatus_set (hw_status | RNG_ENABLED);
  107. if (new_status & RNG_ENABLED)
  108. printk (KERN_INFO PFX "RNG h/w enabledn");
  109. else {
  110. printk (KERN_ERR PFX "Unable to enable the RNGn");
  111. rc = -EIO;
  112. }
  113. }
  114. DPRINTK ("EXIT, returning %dn", rc);
  115. return rc;
  116. }
  117. /*
  118.  * rng_disable - disable the RNG hardware
  119.  */
  120. static void rng_disable(void)
  121. {
  122. u8 hw_status, new_status;
  123. DPRINTK ("ENTERn");
  124. hw_status = rng_hwstatus ();
  125. if (hw_status & RNG_ENABLED) {
  126. new_status = rng_hwstatus_set (hw_status & ~RNG_ENABLED);
  127. if ((new_status & RNG_ENABLED) == 0)
  128. printk (KERN_INFO PFX "RNG h/w disabledn");
  129. else {
  130. printk (KERN_ERR PFX "Unable to disable the RNGn");
  131. }
  132. }
  133. DPRINTK ("EXITn");
  134. }
  135. static int rng_dev_open (struct inode *inode, struct file *filp)
  136. {
  137. int rc;
  138. if ((filp->f_mode & FMODE_READ) == 0)
  139. return -EINVAL;
  140. if (filp->f_mode & FMODE_WRITE)
  141. return -EINVAL;
  142. /* wait for device to become free */
  143. if (filp->f_flags & O_NONBLOCK) {
  144. if (down_trylock (&rng_open_sem))
  145. return -EAGAIN;
  146. } else {
  147. if (down_interruptible (&rng_open_sem))
  148. return -ERESTARTSYS;
  149. }
  150. rc = rng_enable ();
  151. if (rc) {
  152. up (&rng_open_sem);
  153. return rc;
  154. }
  155. return 0;
  156. }
  157. static int rng_dev_release (struct inode *inode, struct file *filp)
  158. {
  159. rng_disable ();
  160. up (&rng_open_sem);
  161. return 0;
  162. }
  163. static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size,
  164.      loff_t * offp)
  165. {
  166. static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED;
  167. int have_data;
  168. u8 data = 0;
  169. ssize_t ret = 0;
  170. while (size) {
  171. spin_lock (&rng_lock);
  172. have_data = 0;
  173. if (rng_data_present ()) {
  174. data = rng_data_read ();
  175. have_data = 1;
  176. }
  177. spin_unlock (&rng_lock);
  178. if (have_data) {
  179. if (put_user (data, buf++)) {
  180. ret = ret ? : -EFAULT;
  181. break;
  182. }
  183. size--;
  184. ret++;
  185. }
  186. if (filp->f_flags & O_NONBLOCK)
  187. return ret ? : -EAGAIN;
  188. current->state = TASK_INTERRUPTIBLE;
  189. schedule_timeout(1);
  190. if (signal_pending (current))
  191. return ret ? : -ERESTARTSYS;
  192. }
  193. return ret;
  194. }
  195. static struct file_operations rng_chrdev_ops = {
  196. owner: THIS_MODULE,
  197. open: rng_dev_open,
  198. release: rng_dev_release,
  199. read: rng_dev_read,
  200. };
  201. static struct miscdevice rng_miscdev = {
  202. RNG_MISCDEV_MINOR,
  203. RNG_MODULE_NAME,
  204. &rng_chrdev_ops,
  205. };
  206. /*
  207.  * rng_init_one - look for and attempt to init a single RNG
  208.  */
  209. static int __init rng_init_one (struct pci_dev *dev)
  210. {
  211. int rc;
  212. u8 hw_status;
  213. DPRINTK ("ENTERn");
  214. rc = misc_register (&rng_miscdev);
  215. if (rc) {
  216. printk (KERN_ERR PFX "cannot register misc devicen");
  217. DPRINTK ("EXIT, returning %dn", rc);
  218. goto err_out;
  219. }
  220. rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN);
  221. if (rng_mem == NULL) {
  222. printk (KERN_ERR PFX "cannot ioremap RNG Memoryn");
  223. DPRINTK ("EXIT, returning -EBUSYn");
  224. rc = -EBUSY;
  225. goto err_out_free_miscdev;
  226. }
  227. /* Check for Intel 82802 */
  228. hw_status = rng_hwstatus ();
  229. if ((hw_status & RNG_PRESENT) == 0) {
  230. printk (KERN_ERR PFX "RNG not detectedn");
  231. DPRINTK ("EXIT, returning -ENODEVn");
  232. rc = -ENODEV;
  233. goto err_out_free_map;
  234. }
  235. /* turn RNG h/w off, if it's on */
  236. if (hw_status & RNG_ENABLED)
  237. hw_status = rng_hwstatus_set (hw_status & ~RNG_ENABLED);
  238. if (hw_status & RNG_ENABLED) {
  239. printk (KERN_ERR PFX "cannot disable RNG, abortingn");
  240. goto err_out_free_map;
  241. }
  242. DPRINTK ("EXIT, returning 0n");
  243. return 0;
  244. err_out_free_map:
  245. iounmap (rng_mem);
  246. err_out_free_miscdev:
  247. misc_deregister (&rng_miscdev);
  248. err_out:
  249. return rc;
  250. }
  251. /*
  252.  * Data for PCI driver interface
  253.  *
  254.  * This data only exists for exporting the supported
  255.  * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
  256.  * register a pci_driver, because someone else might one day
  257.  * want to register another driver on the same PCI id.
  258.  */
  259. static struct pci_device_id rng_pci_tbl[] __initdata = {
  260. { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, },
  261. { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, },
  262. { 0x8086, 0x1130, PCI_ANY_ID, PCI_ANY_ID, },
  263. { 0, },
  264. };
  265. MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
  266. MODULE_AUTHOR("Jeff Garzik, Philipp Rumpf, Matt Sottek");
  267. MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver");
  268. MODULE_LICENSE("GPL");
  269. /*
  270.  * rng_init - initialize RNG module
  271.  */
  272. static int __init rng_init (void)
  273. {
  274. int rc;
  275. struct pci_dev *pdev;
  276. DPRINTK ("ENTERn");
  277. init_MUTEX (&rng_open_sem);
  278. pci_for_each_dev(pdev) {
  279. if (pci_match_device (rng_pci_tbl, pdev) != NULL)
  280. goto match;
  281. }
  282. DPRINTK ("EXIT, returning -ENODEVn");
  283. return -ENODEV;
  284. match:
  285. rc = rng_init_one (pdev);
  286. if (rc)
  287. return rc;
  288. printk (KERN_INFO RNG_DRIVER_NAME " loadedn");
  289. DPRINTK ("EXIT, returning 0n");
  290. return 0;
  291. }
  292. /*
  293.  * rng_init - shutdown RNG module
  294.  */
  295. static void __exit rng_cleanup (void)
  296. {
  297. DPRINTK ("ENTERn");
  298. misc_deregister (&rng_miscdev);
  299. iounmap (rng_mem);
  300. DPRINTK ("EXITn");
  301. }
  302. module_init (rng_init);
  303. module_exit (rng_cleanup);