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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [devices.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
 *  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
 *  (changed to kmod)
10
 */
11
 
12
#include <linux/config.h>
13
#include <linux/fs.h>
14
#include <linux/major.h>
15
#include <linux/string.h>
16
#include <linux/sched.h>
17
#include <linux/stat.h>
18
#include <linux/fcntl.h>
19
#include <linux/errno.h>
20
#include <linux/module.h>
21
#include <linux/smp_lock.h>
22
#ifdef CONFIG_KMOD
23
#include <linux/kmod.h>
24
 
25
#include <linux/tty.h>
26
 
27
/* serial module kmod load support */
28
struct tty_driver *get_tty_driver(kdev_t device);
29
#define isa_tty_dev(ma) (ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
30
#define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL)
31
#endif
32
 
33
struct device_struct {
34
        const char * name;
35
        struct file_operations * fops;
36
};
37
 
38
static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED;
39
static struct device_struct chrdevs[MAX_CHRDEV];
40
 
41
extern int get_blkdev_list(char *);
42
 
43
int get_device_list(char * page)
44
{
45
        int i;
46
        int len;
47
 
48
        len = sprintf(page, "Character devices:\n");
49
        read_lock(&chrdevs_lock);
50
        for (i = 0; i < MAX_CHRDEV ; i++) {
51
                if (chrdevs[i].fops) {
52
                        len += sprintf(page+len, "%3d %s\n", i, chrdevs[i].name);
53
                }
54
        }
55
        read_unlock(&chrdevs_lock);
56
        len += get_blkdev_list(page+len);
57
        return len;
58
}
59
 
60
/*
61
        Return the function table of a device.
62
        Load the driver if needed.
63
        Increment the reference count of module in question.
64
*/
65
static struct file_operations * get_chrfops(unsigned int major, unsigned int minor)
66
{
67
        struct file_operations *ret = NULL;
68
 
69
        if (!major || major >= MAX_CHRDEV)
70
                return NULL;
71
 
72
        read_lock(&chrdevs_lock);
73
        ret = fops_get(chrdevs[major].fops);
74
        read_unlock(&chrdevs_lock);
75
#ifdef CONFIG_KMOD
76
        if (ret && isa_tty_dev(major)) {
77
                lock_kernel();
78
                if (need_serial(major,minor)) {
79
                        /* Force request_module anyway, but what for? */
80
                        fops_put(ret);
81
                        ret = NULL;
82
                }
83
                unlock_kernel();
84
        }
85
        if (!ret) {
86
                char name[20];
87
                sprintf(name, "char-major-%d", major);
88
                request_module(name);
89
 
90
                read_lock(&chrdevs_lock);
91
                ret = fops_get(chrdevs[major].fops);
92
                read_unlock(&chrdevs_lock);
93
        }
94
#endif
95
        return ret;
96
}
97
 
98
int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
99
{
100
        if (major == 0) {
101
                write_lock(&chrdevs_lock);
102
                for (major = MAX_CHRDEV-1; major > 0; major--) {
103
                        if (chrdevs[major].fops == NULL) {
104
                                chrdevs[major].name = name;
105
                                chrdevs[major].fops = fops;
106
                                write_unlock(&chrdevs_lock);
107
                                return major;
108
                        }
109
                }
110
                write_unlock(&chrdevs_lock);
111
                return -EBUSY;
112
        }
113
        if (major >= MAX_CHRDEV)
114
                return -EINVAL;
115
        write_lock(&chrdevs_lock);
116
        if (chrdevs[major].fops && chrdevs[major].fops != fops) {
117
                write_unlock(&chrdevs_lock);
118
                return -EBUSY;
119
        }
120
        chrdevs[major].name = name;
121
        chrdevs[major].fops = fops;
122
        write_unlock(&chrdevs_lock);
123
        return 0;
124
}
125
 
126
int unregister_chrdev(unsigned int major, const char * name)
127
{
128
        if (major >= MAX_CHRDEV)
129
                return -EINVAL;
130
        write_lock(&chrdevs_lock);
131
        if (!chrdevs[major].fops || strcmp(chrdevs[major].name, name)) {
132
                write_unlock(&chrdevs_lock);
133
                return -EINVAL;
134
        }
135
        chrdevs[major].name = NULL;
136
        chrdevs[major].fops = NULL;
137
        write_unlock(&chrdevs_lock);
138
        return 0;
139
}
140
 
141
/*
142
 * Called every time a character special file is opened
143
 */
144
int chrdev_open(struct inode * inode, struct file * filp)
145
{
146
        int ret = -ENODEV;
147
 
148
        filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
149
        if (filp->f_op) {
150
                ret = 0;
151
                if (filp->f_op->open != NULL) {
152
                        lock_kernel();
153
                        ret = filp->f_op->open(inode,filp);
154
                        unlock_kernel();
155
                }
156
        }
157
        return ret;
158
}
159
 
160
/*
161
 * Dummy default file-operations: the only thing this does
162
 * is contain the open that then fills in the correct operations
163
 * depending on the special file...
164
 */
165
static struct file_operations def_chr_fops = {
166
        open:           chrdev_open,
167
};
168
 
169
/*
170
 * Print device name (in decimal, hexadecimal or symbolic)
171
 * Note: returns pointer to static data!
172
 */
173
const char * kdevname(kdev_t dev)
174
{
175
        static char buffer[32];
176
        sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
177
        return buffer;
178
}
179
 
180
const char * cdevname(kdev_t dev)
181
{
182
        static char buffer[32];
183
        const char * name = chrdevs[MAJOR(dev)].name;
184
 
185
        if (!name)
186
                name = "unknown-char";
187
        sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
188
        return buffer;
189
}
190
 
191
static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
192
{
193
        return -ENXIO;
194
}
195
 
196
static struct file_operations bad_sock_fops = {
197
        open:           sock_no_open
198
};
199
 
200
void init_special_inode(struct inode *inode, umode_t mode, int rdev)
201
{
202
        inode->i_mode = mode;
203
        if (S_ISCHR(mode)) {
204
                inode->i_fop = &def_chr_fops;
205
                inode->i_rdev = to_kdev_t(rdev);
206
                inode->i_cdev = cdget(rdev);
207
        } else if (S_ISBLK(mode)) {
208
                inode->i_fop = &def_blk_fops;
209
                inode->i_rdev = to_kdev_t(rdev);
210
        } else if (S_ISFIFO(mode))
211
                inode->i_fop = &def_fifo_fops;
212
        else if (S_ISSOCK(mode))
213
                inode->i_fop = &bad_sock_fops;
214
        else
215
                printk(KERN_DEBUG "init_special_inode: bogus imode (%o)\n", mode);
216
}

powered by: WebSVN 2.1.0

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