Linux 2.2.0
[davej-history.git] / fs / devices.c
blob2ff69850a1b562b60a2753029a940974f164985d
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/sched.h>
17 #include <linux/stat.h>
18 #include <linux/fcntl.h>
19 #include <linux/errno.h>
20 #ifdef CONFIG_KMOD
21 #include <linux/kmod.h>
23 #include <linux/tty.h>
25 /* serial module kmod 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
31 struct device_struct {
32 const char * name;
33 struct file_operations * fops;
36 static struct device_struct chrdevs[MAX_CHRDEV] = {
37 { NULL, NULL },
40 static struct device_struct blkdevs[MAX_BLKDEV] = {
41 { NULL, NULL },
44 int get_device_list(char * page)
46 int i;
47 int len;
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, "%3d %s\n", i, chrdevs[i].name);
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, "%3d %s\n", i, blkdevs[i].name);
61 return len;
65 Return the function table of a device.
66 Load the driver if needed.
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[])
75 struct file_operations *ret = NULL;
77 if (major < maxdev){
78 #ifdef CONFIG_KMOD
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 kmod and modprobe for nothing (since there
84 * is no device with major number == 0. And furthermore
85 * it locks the reboot process :-(
87 * Jacques Gelinas (jacques@solucorp.qc.ca)
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 kmod
92 * as there is no other loadable dev on these majors
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);
100 #endif
101 ret = tb[major].fops;
103 return ret;
108 Return the function table of a device.
109 Load the driver if needed.
111 struct file_operations * get_blkfops(unsigned int major)
113 return get_fops (major,0,MAX_BLKDEV,"block-major-%d",blkdevs);
116 struct file_operations * get_chrfops(unsigned int major, unsigned int minor)
118 return get_fops (major,minor,MAX_CHRDEV,"char-major-%d",chrdevs);
121 int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
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;
131 return -EBUSY;
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;
142 int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
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;
152 return -EBUSY;
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;
163 int unregister_chrdev(unsigned int major, const char * name)
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;
176 int unregister_blkdev(unsigned int major, const char * name)
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;
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 :-)
198 int check_disk_change(kdev_t dev)
200 int i;
201 struct file_operations * fops;
202 struct super_block * sb;
204 i = MAJOR(dev);
205 if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
206 return 0;
207 if (fops->check_media_change == NULL)
208 return 0;
209 if (!fops->check_media_change(dev))
210 return 0;
212 printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
213 bdevname(dev));
215 sb = get_super(dev);
216 if (sb && invalidate_inodes(sb))
217 printk("VFS: busy inodes on changed media.\n");
219 invalidate_buffers(dev);
221 if (fops->revalidate)
222 fops->revalidate(dev);
223 return 1;
227 * Called every time a block special file is opened
229 int blkdev_open(struct inode * inode, struct file * filp)
231 int ret = -ENODEV;
232 filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
233 if (filp->f_op != NULL){
234 ret = 0;
235 if (filp->f_op->open != NULL)
236 ret = filp->f_op->open(inode,filp);
238 return ret;
241 int blkdev_release(struct inode * inode)
243 struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
244 if (fops && fops->release)
245 return fops->release(inode,NULL);
246 return 0;
251 * Dummy default file-operations: the only thing this does
252 * is contain the open that then fills in the correct operations
253 * depending on the special file...
255 struct file_operations def_blk_fops = {
256 NULL, /* lseek */
257 NULL, /* read */
258 NULL, /* write */
259 NULL, /* readdir */
260 NULL, /* poll */
261 NULL, /* ioctl */
262 NULL, /* mmap */
263 blkdev_open, /* open */
264 NULL, /* flush */
265 NULL, /* release */
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, /* readpage */
281 NULL, /* writepage */
282 NULL, /* bmap */
283 NULL, /* truncate */
284 NULL /* permission */
288 * Called every time a character special file is opened
290 int chrdev_open(struct inode * inode, struct file * filp)
292 int ret = -ENODEV;
294 filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
295 if (filp->f_op != NULL){
296 ret = 0;
297 if (filp->f_op->open != NULL)
298 ret = filp->f_op->open(inode,filp);
300 return ret;
304 * Dummy default file-operations: the only thing this does
305 * is contain the open that then fills in the correct operations
306 * depending on the special file...
308 struct file_operations def_chr_fops = {
309 NULL, /* lseek */
310 NULL, /* read */
311 NULL, /* write */
312 NULL, /* readdir */
313 NULL, /* poll */
314 NULL, /* ioctl */
315 NULL, /* mmap */
316 chrdev_open, /* open */
317 NULL, /* flush */
318 NULL, /* release */
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, /* readpage */
334 NULL, /* writepage */
335 NULL, /* bmap */
336 NULL, /* truncate */
337 NULL /* permission */
341 * Print device name (in decimal, hexadecimal or symbolic)
342 * Note: returns pointer to static data!
344 char * kdevname(kdev_t dev)
346 static char buffer[32];
347 sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
348 return buffer;
351 char * bdevname(kdev_t dev)
353 static char buffer[32];
354 const char * name = blkdevs[MAJOR(dev)].name;
356 if (!name)
357 name = "unknown-block";
359 sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
360 return buffer;
363 char * cdevname(kdev_t dev)
365 static char buffer[32];
366 const char * name = chrdevs[MAJOR(dev)].name;
368 if (!name)
369 name = "unknown-char";
370 sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
371 return buffer;