The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/devices.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 #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 }

Cache object: beda5143c3e6e9ab45d6e8fd2f146aac


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.