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

Subversion Repositories or1k

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

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

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

powered by: WebSVN 2.1.0

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