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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [fs/] [devices.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/fs/devices.c
3
 *
4
 * (C) 1993 Matthias Urlichs -- collected common code and tables.
5
 *
6
 *  Copyright (C) 1991, 1992  Linus Torvalds
7
 *
8
 *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
9
 */
10
 
11
#include <linux/config.h>
12
#include <linux/fs.h>
13
#include <linux/major.h>
14
#include <linux/string.h>
15
#include <linux/sched.h>
16
#include <linux/ext_fs.h>
17
#include <linux/stat.h>
18
#include <linux/fcntl.h>
19
#include <linux/errno.h>
20
#ifdef CONFIG_KERNELD
21
#include <linux/kerneld.h>
22
 
23
#include <linux/tty.h>
24
 
25
/* serial module kerneld load support */
26
struct tty_driver *get_tty_driver(kdev_t device);
27
#define isa_tty_dev(ma) (ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
28
#define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL)
29
#endif
30
 
31
struct device_struct {
32
        const char * name;
33
        struct file_operations * fops;
34
};
35
 
36
static struct device_struct chrdevs[MAX_CHRDEV] = {
37
        { NULL, NULL },
38
};
39
 
40
static struct device_struct blkdevs[MAX_BLKDEV] = {
41
        { NULL, NULL },
42
};
43
 
44
int get_device_list(char * page)
45
{
46
        int i;
47
        int len;
48
 
49
        len = sprintf(page, "Character devices:\n");
50
        for (i = 0; i < MAX_CHRDEV ; i++) {
51
                if (chrdevs[i].fops) {
52
                        len += sprintf(page+len, "%2d %s\n", i, chrdevs[i].name);
53
                }
54
        }
55
        len += sprintf(page+len, "\nBlock devices:\n");
56
        for (i = 0; i < MAX_BLKDEV ; i++) {
57
                if (blkdevs[i].fops) {
58
                        len += sprintf(page+len, "%2d %s\n", i, blkdevs[i].name);
59
                }
60
        }
61
        return len;
62
}
63
 
64
/*
65
        Return the function table of a device.
66
        Load the driver if needed.
67
*/
68
static struct file_operations * get_fops(
69
        unsigned int major,
70
        unsigned int minor,
71
        unsigned int maxdev,
72
        const char *mangle,             /* String to use to build the module name */
73
        struct device_struct tb[])
74
{
75
        struct file_operations *ret = NULL;
76
 
77
        if (major < maxdev){
78
#ifdef CONFIG_KERNELD
79
                /*
80
                 * I do get request for device 0. I have no idea why. It happen
81
                 * at shutdown time for one. Without the following test, the
82
                 * kernel will happily trigger a request_module() which will
83
                 * trigger kerneld and modprobe for nothing (since there
84
                 * is no device with major number == 0. And furthermore
85
                 * it locks the reboot process :-(
86
                 *
87
                 * Jacques Gelinas (jacques@solucorp.qc.ca)
88
                 *
89
                 * A. Haritsis <ah@doc.ic.ac.uk>: fix for serial module
90
                 *  though we need the minor here to check if serial dev,
91
                 *  we pass only the normal major char dev to kerneld
92
                 *  as there is no other loadable dev on these majors
93
                 */
94
                if ((isa_tty_dev(major) && need_serial(major,minor)) ||
95
                    (major != 0 && !tb[major].fops)) {
96
                        char name[20];
97
                        sprintf(name, mangle, major);
98
                        request_module(name);
99
                }
100
#endif
101
                ret = tb[major].fops;
102
        }
103
        return ret;
104
}
105
 
106
 
107
/*
108
        Return the function table of a device.
109
        Load the driver if needed.
110
*/
111
struct file_operations * get_blkfops(unsigned int major)
112
{
113
        return get_fops (major,0,MAX_BLKDEV,"block-major-%d",blkdevs);
114
}
115
 
116
struct file_operations * get_chrfops(unsigned int major, unsigned int minor)
117
{
118
        return get_fops (major,minor,MAX_CHRDEV,"char-major-%d",chrdevs);
119
}
120
 
121
int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
122
{
123
        if (major == 0) {
124
                for (major = MAX_CHRDEV-1; major > 0; major--) {
125
                        if (chrdevs[major].fops == NULL) {
126
                                chrdevs[major].name = name;
127
                                chrdevs[major].fops = fops;
128
                                return major;
129
                        }
130
                }
131
                return -EBUSY;
132
        }
133
        if (major >= MAX_CHRDEV)
134
                return -EINVAL;
135
        if (chrdevs[major].fops && chrdevs[major].fops != fops)
136
                return -EBUSY;
137
        chrdevs[major].name = name;
138
        chrdevs[major].fops = fops;
139
        return 0;
140
}
141
 
142
int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
143
{
144
        if (major == 0) {
145
                for (major = MAX_BLKDEV-1; major > 0; major--) {
146
                        if (blkdevs[major].fops == NULL) {
147
                                blkdevs[major].name = name;
148
                                blkdevs[major].fops = fops;
149
                                return major;
150
                        }
151
                }
152
                return -EBUSY;
153
        }
154
        if (major >= MAX_BLKDEV)
155
                return -EINVAL;
156
        if (blkdevs[major].fops && blkdevs[major].fops != fops)
157
                return -EBUSY;
158
        blkdevs[major].name = name;
159
        blkdevs[major].fops = fops;
160
        return 0;
161
}
162
 
163
int unregister_chrdev(unsigned int major, const char * name)
164
{
165
        if (major >= MAX_CHRDEV)
166
                return -EINVAL;
167
        if (!chrdevs[major].fops)
168
                return -EINVAL;
169
        if (strcmp(chrdevs[major].name, name))
170
                return -EINVAL;
171
        chrdevs[major].name = NULL;
172
        chrdevs[major].fops = NULL;
173
        return 0;
174
}
175
 
176
int unregister_blkdev(unsigned int major, const char * name)
177
{
178
        if (major >= MAX_BLKDEV)
179
                return -EINVAL;
180
        if (!blkdevs[major].fops)
181
                return -EINVAL;
182
        if (strcmp(blkdevs[major].name, name))
183
                return -EINVAL;
184
        blkdevs[major].name = NULL;
185
        blkdevs[major].fops = NULL;
186
        return 0;
187
}
188
 
189
/*
190
 * This routine checks whether a removable media has been changed,
191
 * and invalidates all buffer-cache-entries in that case. This
192
 * is a relatively slow routine, so we have to try to minimize using
193
 * it. Thus it is called only upon a 'mount' or 'open'. This
194
 * is the best way of combining speed and utility, I think.
195
 * People changing diskettes in the middle of an operation deserve
196
 * to loose :-)
197
 */
198
int check_disk_change(kdev_t dev)
199
{
200
        int i;
201
        struct file_operations * fops;
202
 
203
        i = MAJOR(dev);
204
        if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
205
                return 0;
206
        if (fops->check_media_change == NULL)
207
                return 0;
208
        if (!fops->check_media_change(dev))
209
                return 0;
210
 
211
        printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
212
                kdevname(dev));
213
        for (i=0 ; i<NR_SUPER ; i++)
214
                if (super_blocks[i].s_dev == dev)
215
                        put_super(super_blocks[i].s_dev);
216
        invalidate_inodes(dev);
217
        invalidate_buffers(dev);
218
 
219
        if (fops->revalidate)
220
                fops->revalidate(dev);
221
        return 1;
222
}
223
 
224
/*
225
 * Called every time a block special file is opened
226
 */
227
int blkdev_open(struct inode * inode, struct file * filp)
228
{
229
        int ret = -ENODEV;
230
 
231
        if (securelevel > 0 && (filp->f_mode & FMODE_WRITE))
232
                return -EACCES; /* cevans */
233
 
234
        filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
235
        if (filp->f_op != NULL){
236
                ret = 0;
237
                if (filp->f_op->open != NULL)
238
                        ret = filp->f_op->open(inode,filp);
239
        }
240
        return ret;
241
}
242
 
243
void blkdev_release(struct inode * inode)
244
{
245
        struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
246
        if (fops && fops->release)
247
                fops->release(inode,NULL);
248
}
249
 
250
 
251
/*
252
 * Dummy default file-operations: the only thing this does
253
 * is contain the open that then fills in the correct operations
254
 * depending on the special file...
255
 */
256
struct file_operations def_blk_fops = {
257
        NULL,           /* lseek */
258
        NULL,           /* read */
259
        NULL,           /* write */
260
        NULL,           /* readdir */
261
        NULL,           /* select */
262
        NULL,           /* ioctl */
263
        NULL,           /* mmap */
264
        blkdev_open,    /* open */
265
        NULL,           /* release */
266
};
267
 
268
struct inode_operations blkdev_inode_operations = {
269
        &def_blk_fops,          /* default file operations */
270
        NULL,                   /* create */
271
        NULL,                   /* lookup */
272
        NULL,                   /* link */
273
        NULL,                   /* unlink */
274
        NULL,                   /* symlink */
275
        NULL,                   /* mkdir */
276
        NULL,                   /* rmdir */
277
        NULL,                   /* mknod */
278
        NULL,                   /* rename */
279
        NULL,                   /* readlink */
280
        NULL,                   /* follow_link */
281
        NULL,                   /* readpage */
282
        NULL,                   /* writepage */
283
        NULL,                   /* bmap */
284
        NULL,                   /* truncate */
285
        NULL                    /* permission */
286
};
287
 
288
/*
289
 * Called every time a character special file is opened
290
 */
291
int chrdev_open(struct inode * inode, struct file * filp)
292
{
293
        int ret = -ENODEV;
294
 
295
        filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
296
        if (filp->f_op != NULL){
297
                ret = 0;
298
                if (filp->f_op->open != NULL)
299
                        ret = filp->f_op->open(inode,filp);
300
        }
301
        return ret;
302
}
303
 
304
/*
305
 * Dummy default file-operations: the only thing this does
306
 * is contain the open that then fills in the correct operations
307
 * depending on the special file...
308
 */
309
struct file_operations def_chr_fops = {
310
        NULL,           /* lseek */
311
        NULL,           /* read */
312
        NULL,           /* write */
313
        NULL,           /* readdir */
314
        NULL,           /* select */
315
        NULL,           /* ioctl */
316
        NULL,           /* mmap */
317
        chrdev_open,    /* open */
318
        NULL,           /* release */
319
};
320
 
321
struct inode_operations chrdev_inode_operations = {
322
        &def_chr_fops,          /* default file operations */
323
        NULL,                   /* create */
324
        NULL,                   /* lookup */
325
        NULL,                   /* link */
326
        NULL,                   /* unlink */
327
        NULL,                   /* symlink */
328
        NULL,                   /* mkdir */
329
        NULL,                   /* rmdir */
330
        NULL,                   /* mknod */
331
        NULL,                   /* rename */
332
        NULL,                   /* readlink */
333
        NULL,                   /* follow_link */
334
        NULL,                   /* readpage */
335
        NULL,                   /* writepage */
336
        NULL,                   /* bmap */
337
        NULL,                   /* truncate */
338
        NULL                    /* permission */
339
};
340
 
341
/*
342
 * Print device name (in decimal, hexadecimal or symbolic) -
343
 * at present hexadecimal only.
344
 * Note: returns pointer to static data!
345
 */
346
char * kdevname(kdev_t dev)
347
{
348
        static char buffer[32];
349
        sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
350
        return buffer;
351
}

powered by: WebSVN 2.1.0

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