Pull one more egcs 1.1.2 workaround.
[linux-2.6/linux-mips.git] / fs / devices.c
blob1b8f3e2546e3c0ad42ad49c68e419c68aa090980
1 /*
2 * linux/fs/devices.c
4 * (C) 1993 Matthias Urlichs -- collected common code and tables.
5 *
6 * Copyright (C) 1991, 1992 Linus Torvalds
8 * Added kerneld support: Jacques Gelinas and Bjorn Ekwall
9 * (changed to kmod)
12 #include <linux/config.h>
13 #include <linux/fs.h>
14 #include <linux/major.h>
15 #include <linux/string.h>
16 #include <linux/time.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 #include <linux/devfs_fs_kernel.h>
23 #ifdef CONFIG_KMOD
24 #include <linux/kmod.h>
26 #include <linux/tty.h>
28 /* serial module kmod load support */
29 struct tty_driver *get_tty_driver(kdev_t device);
30 #define isa_tty_dev(ma) (ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
31 #define need_serial(ma,mi) (get_tty_driver(mk_kdev(ma,mi)) == NULL)
32 #endif
34 struct device_struct {
35 const char * name;
36 struct file_operations * fops;
39 static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED;
40 static struct device_struct chrdevs[MAX_CHRDEV];
42 extern int get_blkdev_list(char *);
44 int get_device_list(char * page)
46 int i;
47 int len;
49 len = sprintf(page, "Character devices:\n");
50 read_lock(&chrdevs_lock);
51 for (i = 0; i < MAX_CHRDEV ; i++) {
52 if (chrdevs[i].fops) {
53 len += sprintf(page+len, "%3d %s\n", i, chrdevs[i].name);
56 read_unlock(&chrdevs_lock);
57 len += get_blkdev_list(page+len);
58 return len;
62 Return the function table of a device.
63 Load the driver if needed.
64 Increment the reference count of module in question.
66 static struct file_operations * get_chrfops(unsigned int major, unsigned int minor)
68 struct file_operations *ret = NULL;
70 if (!major || major >= MAX_CHRDEV)
71 return NULL;
73 read_lock(&chrdevs_lock);
74 ret = fops_get(chrdevs[major].fops);
75 read_unlock(&chrdevs_lock);
76 #ifdef CONFIG_KMOD
77 if (ret && isa_tty_dev(major)) {
78 lock_kernel();
79 if (need_serial(major,minor)) {
80 /* Force request_module anyway, but what for? */
81 fops_put(ret);
82 ret = NULL;
84 unlock_kernel();
86 if (!ret) {
87 char name[20];
88 sprintf(name, "char-major-%d", major);
89 request_module(name);
91 read_lock(&chrdevs_lock);
92 ret = fops_get(chrdevs[major].fops);
93 read_unlock(&chrdevs_lock);
95 #endif
96 return ret;
99 int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
101 if (devfs_only())
102 return 0;
103 if (major == 0) {
104 write_lock(&chrdevs_lock);
105 for (major = MAX_CHRDEV-1; major > 0; major--) {
106 if (chrdevs[major].fops == NULL) {
107 chrdevs[major].name = name;
108 chrdevs[major].fops = fops;
109 write_unlock(&chrdevs_lock);
110 return major;
113 write_unlock(&chrdevs_lock);
114 return -EBUSY;
116 if (major >= MAX_CHRDEV)
117 return -EINVAL;
118 write_lock(&chrdevs_lock);
119 if (chrdevs[major].fops && chrdevs[major].fops != fops) {
120 write_unlock(&chrdevs_lock);
121 return -EBUSY;
123 chrdevs[major].name = name;
124 chrdevs[major].fops = fops;
125 write_unlock(&chrdevs_lock);
126 return 0;
129 int unregister_chrdev(unsigned int major, const char * name)
131 if (devfs_only())
132 return 0;
133 if (major >= MAX_CHRDEV)
134 return -EINVAL;
135 write_lock(&chrdevs_lock);
136 if (!chrdevs[major].fops || strcmp(chrdevs[major].name, name)) {
137 write_unlock(&chrdevs_lock);
138 return -EINVAL;
140 chrdevs[major].name = NULL;
141 chrdevs[major].fops = NULL;
142 write_unlock(&chrdevs_lock);
143 return 0;
147 * Called every time a character special file is opened
149 int chrdev_open(struct inode * inode, struct file * filp)
151 int ret = -ENODEV;
153 filp->f_op = get_chrfops(major(inode->i_rdev), minor(inode->i_rdev));
154 if (filp->f_op) {
155 ret = 0;
156 if (filp->f_op->open != NULL) {
157 lock_kernel();
158 ret = filp->f_op->open(inode,filp);
159 unlock_kernel();
162 return ret;
166 * Dummy default file-operations: the only thing this does
167 * is contain the open that then fills in the correct operations
168 * depending on the special file...
170 static struct file_operations def_chr_fops = {
171 .open = chrdev_open,
175 * Print device name (in decimal, hexadecimal or symbolic)
176 * Note: returns pointer to static data!
178 const char * kdevname(kdev_t dev)
180 static char buffer[32];
181 sprintf(buffer, "%02x:%02x", major(dev), minor(dev));
182 return buffer;
185 const char * cdevname(kdev_t dev)
187 static char buffer[32];
188 const char * name = chrdevs[major(dev)].name;
190 if (!name)
191 name = "unknown-char";
192 sprintf(buffer, "%s(%d,%d)", name, major(dev), minor(dev));
193 return buffer;
196 static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
198 return -ENXIO;
201 static struct file_operations bad_sock_fops = {
202 .open = sock_no_open
205 void init_special_inode(struct inode *inode, umode_t mode, int rdev)
207 inode->i_mode = mode;
208 if (S_ISCHR(mode)) {
209 inode->i_fop = &def_chr_fops;
210 inode->i_rdev = to_kdev_t(rdev);
211 inode->i_cdev = cdget(rdev);
212 } else if (S_ISBLK(mode)) {
213 inode->i_fop = &def_blk_fops;
214 inode->i_rdev = to_kdev_t(rdev);
215 } else if (S_ISFIFO(mode))
216 inode->i_fop = &def_fifo_fops;
217 else if (S_ISSOCK(mode))
218 inode->i_fop = &bad_sock_fops;
219 else
220 printk(KERN_DEBUG "init_special_inode: bogus imode (%o)\n", mode);