OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [i810_rng.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.