linux-old/fs/devices.c
<<
>>
Prefs
   1/*
   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#ifdef CONFIG_KMOD
  21#include <linux/kmod.h>
  22
  23#include <linux/tty.h>
  24
  25/* serial module kmod load support */
  26struct 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
  31struct device_struct {
  32        const char * name;
  33        struct file_operations * fops;
  34};
  35
  36static struct device_struct chrdevs[MAX_CHRDEV] = {
  37        { NULL, NULL },
  38};
  39
  40static struct device_struct blkdevs[MAX_BLKDEV] = {
  41        { NULL, NULL },
  42};
  43
  44int 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, "%3d %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, "%3d %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*/
  68static 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_KMOD
  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 kmod 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 kmod 
  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*/
 111struct file_operations * get_blkfops(unsigned int major)
 112{
 113        return get_fops (major,0,MAX_BLKDEV,"block-major-%d",blkdevs);
 114}
 115
 116struct 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
 121int 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
 142int 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
 163int 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
 176int 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 */
 198int check_disk_change(kdev_t dev)
 199{
 200        int i;
 201        struct file_operations * fops;
 202        struct super_block * sb;
 203
 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;
 211
 212        printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
 213                bdevname(dev));
 214
 215        sb = get_super(dev);
 216        if (sb && invalidate_inodes(sb))
 217                printk("VFS: busy inodes on changed media.\n");
 218
 219        /* special: trash all dirty data as well as the media is changed */
 220        destroy_buffers(dev);
 221
 222        if (fops->revalidate)
 223                fops->revalidate(dev);
 224        return 1;
 225}
 226
 227/*
 228 * Called every time a block special file is opened
 229 */
 230int blkdev_open(struct inode * inode, struct file * filp)
 231{
 232        int ret = -ENODEV;
 233        filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
 234        if (filp->f_op != NULL){
 235                ret = 0;
 236                if (filp->f_op->open != NULL)
 237                        ret = filp->f_op->open(inode,filp);
 238        }       
 239        return ret;
 240}       
 241
 242int blkdev_release(struct inode * inode)
 243{
 244        struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
 245        if (fops && fops->release)
 246                return fops->release(inode,NULL);
 247        return 0;
 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 */
 256struct file_operations def_blk_fops = {
 257        NULL,           /* lseek */
 258        NULL,           /* read */
 259        NULL,           /* write */
 260        NULL,           /* readdir */
 261        NULL,           /* poll */
 262        NULL,           /* ioctl */
 263        NULL,           /* mmap */
 264        blkdev_open,    /* open */
 265        NULL,           /* flush */
 266        NULL,           /* release */
 267};
 268
 269struct inode_operations blkdev_inode_operations = {
 270        &def_blk_fops,          /* default file operations */
 271        NULL,                   /* create */
 272        NULL,                   /* lookup */
 273        NULL,                   /* link */
 274        NULL,                   /* unlink */
 275        NULL,                   /* symlink */
 276        NULL,                   /* mkdir */
 277        NULL,                   /* rmdir */
 278        NULL,                   /* mknod */
 279        NULL,                   /* rename */
 280        NULL,                   /* readlink */
 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 */
 291int 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 */
 309struct file_operations def_chr_fops = {
 310        NULL,           /* lseek */
 311        NULL,           /* read */
 312        NULL,           /* write */
 313        NULL,           /* readdir */
 314        NULL,           /* poll */
 315        NULL,           /* ioctl */
 316        NULL,           /* mmap */
 317        chrdev_open,    /* open */
 318        NULL,           /* flush */
 319        NULL,           /* release */
 320};
 321
 322struct inode_operations chrdev_inode_operations = {
 323        &def_chr_fops,          /* default file operations */
 324        NULL,                   /* create */
 325        NULL,                   /* lookup */
 326        NULL,                   /* link */
 327        NULL,                   /* unlink */
 328        NULL,                   /* symlink */
 329        NULL,                   /* mkdir */
 330        NULL,                   /* rmdir */
 331        NULL,                   /* mknod */
 332        NULL,                   /* rename */
 333        NULL,                   /* readlink */
 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 * Note: returns pointer to static data!
 344 */
 345char * kdevname(kdev_t dev)
 346{
 347        static char buffer[32];
 348        sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
 349        return buffer;
 350}
 351
 352char * bdevname(kdev_t dev)
 353{
 354        static char buffer[32];
 355        const char * name = blkdevs[MAJOR(dev)].name;
 356
 357        if (!name)
 358                name = "unknown-block";
 359
 360        sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
 361        return buffer;
 362}
 363
 364char * cdevname(kdev_t dev)
 365{
 366        static char buffer[32];
 367        const char * name = chrdevs[MAJOR(dev)].name;
 368
 369        if (!name)
 370                name = "unknown-char";
 371        sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
 372        return buffer;
 373}
 374
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.