RHEL4/fs/char_dev.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/char_dev.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 */
   6
   7#include <linux/config.h>
   8#include <linux/init.h>
   9#include <linux/fs.h>
  10#include <linux/slab.h>
  11#include <linux/string.h>
  12
  13#include <linux/major.h>
  14#include <linux/errno.h>
  15#include <linux/module.h>
  16#include <linux/smp_lock.h>
  17#include <linux/devfs_fs_kernel.h>
  18#ifndef __GENKSYMS__
  19#include <linux/seq_file.h>
  20#endif
  21
  22#include <linux/kobject.h>
  23#include <linux/kobj_map.h>
  24#include <linux/cdev.h>
  25
  26#ifdef CONFIG_KMOD
  27#include <linux/kmod.h>
  28#endif
  29
  30static struct kobj_map *cdev_map;
  31
  32#define MAX_PROBE_HASH 255      /* random */
  33
  34static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED;
  35
  36static struct char_device_struct {
  37        struct char_device_struct *next;
  38        unsigned int major;
  39        unsigned int baseminor;
  40        int minorct;
  41        const char *name;
  42        struct file_operations *fops;
  43        struct cdev *cdev;              /* will die */
  44} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
  45
  46/* index in the above */
  47static inline int major_to_index(int major)
  48{
  49        return major % CHRDEV_MAJOR_HASH_SIZE;
  50}
  51
  52#ifdef CONFIG_PROC_FS
  53
  54void chrdev_show(struct seq_file *f, off_t offset)
  55{
  56        struct char_device_struct *cd;
  57
  58        if (offset < CHRDEV_MAJOR_HASH_SIZE) {
  59                read_lock(&chrdevs_lock);
  60                for (cd = chrdevs[offset]; cd; cd = cd->next)
  61                        seq_printf(f, "%3d %s\n", cd->major, cd->name);
  62                read_unlock(&chrdevs_lock);
  63        }
  64}
  65
  66#endif /* CONFIG_PROC_FS */
  67
  68/* get char device names in somewhat random order */
  69int get_chrdev_list(char *page)
  70{
  71        struct char_device_struct *cd;
  72        int i, len;
  73
  74        len = sprintf(page, "Character devices:\n");
  75
  76        read_lock(&chrdevs_lock);
  77        for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
  78                for (cd = chrdevs[i]; cd; cd = cd->next)
  79                        len += sprintf(page+len, "%3d %s\n",
  80                                       cd->major, cd->name);
  81        }
  82        read_unlock(&chrdevs_lock);
  83
  84        return len;
  85}
  86
  87/*
  88 * Register a single major with a specified minor range.
  89 *
  90 * If major == 0 this functions will dynamically allocate a major and return
  91 * its number.
  92 *
  93 * If major > 0 this function will attempt to reserve the passed range of
  94 * minors and will return zero on success.
  95 *
  96 * Returns a -ve errno on failure.
  97 */
  98static struct char_device_struct *
  99__register_chrdev_region(unsigned int major, unsigned int baseminor,
 100                           int minorct, const char *name)
 101{
 102        struct char_device_struct *cd, **cp;
 103        int ret = 0;
 104        int i;
 105
 106        cd = kmalloc(sizeof(struct char_device_struct), GFP_KERNEL);
 107        if (cd == NULL)
 108                return ERR_PTR(-ENOMEM);
 109
 110        memset(cd, 0, sizeof(struct char_device_struct));
 111
 112        write_lock_irq(&chrdevs_lock);
 113
 114        /* temporary */
 115        if (major == 0) {
 116                for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
 117                        if (chrdevs[i] == NULL)
 118                                break;
 119                }
 120
 121                if (i == 0) {
 122                        ret = -EBUSY;
 123                        goto out;
 124                }
 125                major = i;
 126                ret = major;
 127        }
 128
 129        cd->major = major;
 130        cd->baseminor = baseminor;
 131        cd->minorct = minorct;
 132        cd->name = name;
 133
 134        i = major_to_index(major);
 135
 136        for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
 137                if ((*cp)->major > major ||
 138                    ((*cp)->major == major && (*cp)->baseminor >= baseminor))
 139                        break;
 140        if (*cp && (*cp)->major == major &&
 141            (*cp)->baseminor < baseminor + minorct) {
 142                ret = -EBUSY;
 143                goto out;
 144        }
 145        cd->next = *cp;
 146        *cp = cd;
 147        write_unlock_irq(&chrdevs_lock);
 148        return cd;
 149out:
 150        write_unlock_irq(&chrdevs_lock);
 151        kfree(cd);
 152        return ERR_PTR(ret);
 153}
 154
 155static struct char_device_struct *
 156__unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
 157{
 158        struct char_device_struct *cd = NULL, **cp;
 159        int i = major_to_index(major);
 160
 161        write_lock_irq(&chrdevs_lock);
 162        for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
 163                if ((*cp)->major == major &&
 164                    (*cp)->baseminor == baseminor &&
 165                    (*cp)->minorct == minorct)
 166                        break;
 167        if (*cp) {
 168                cd = *cp;
 169                *cp = cd->next;
 170        }
 171        write_unlock_irq(&chrdevs_lock);
 172        return cd;
 173}
 174
 175int register_chrdev_region(dev_t from, unsigned count, char *name)
 176{
 177        struct char_device_struct *cd;
 178        dev_t to = from + count;
 179        dev_t n, next;
 180
 181        for (n = from; n < to; n = next) {
 182                next = MKDEV(MAJOR(n)+1, 0);
 183                if (next > to)
 184                        next = to;
 185                cd = __register_chrdev_region(MAJOR(n), MINOR(n),
 186                               next - n, name);
 187                if (IS_ERR(cd))
 188                        goto fail;
 189        }
 190        return 0;
 191fail:
 192        to = n;
 193        for (n = from; n < to; n = next) {
 194                next = MKDEV(MAJOR(n)+1, 0);
 195                kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
 196        }
 197        return PTR_ERR(cd);
 198}
 199
 200int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char *name)
 201{
 202        struct char_device_struct *cd;
 203        cd = __register_chrdev_region(0, baseminor, count, name);
 204        if (IS_ERR(cd))
 205                return PTR_ERR(cd);
 206        *dev = MKDEV(cd->major, cd->baseminor);
 207        return 0;
 208}
 209
 210int register_chrdev(unsigned int major, const char *name,
 211                    struct file_operations *fops)
 212{
 213        struct char_device_struct *cd;
 214        struct cdev *cdev;
 215        char *s;
 216        int err = -ENOMEM;
 217
 218        cd = __register_chrdev_region(major, 0, 256, name);
 219        if (IS_ERR(cd))
 220                return PTR_ERR(cd);
 221        
 222        cdev = cdev_alloc();
 223        if (!cdev)
 224                goto out2;
 225
 226        cdev->owner = fops->owner;
 227        cdev->ops = fops;
 228        strcpy(cdev->kobj.name, name);
 229        for (s = strchr(cdev->kobj.name, '/'); s; s = strchr(s, '/'))
 230                *s = '!';
 231                
 232        err = cdev_add(cdev, MKDEV(cd->major, 0), 256);
 233        if (err)
 234                goto out;
 235
 236        cd->cdev = cdev;
 237
 238        return major ? 0 : cd->major;
 239out:
 240        kobject_put(&cdev->kobj);
 241out2:
 242        kfree(__unregister_chrdev_region(cd->major, 0, 256));
 243        return err;
 244}
 245
 246void unregister_chrdev_region(dev_t from, unsigned count)
 247{
 248        dev_t to = from + count;
 249        dev_t n, next;
 250
 251        for (n = from; n < to; n = next) {
 252                next = MKDEV(MAJOR(n)+1, 0);
 253                if (next > to)
 254                        next = to;
 255                kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
 256        }
 257}
 258
 259int unregister_chrdev(unsigned int major, const char *name)
 260{
 261        struct char_device_struct *cd;
 262        cd = __unregister_chrdev_region(major, 0, 256);
 263        if (cd && cd->cdev)
 264                cdev_del(cd->cdev);
 265        kfree(cd);
 266        return 0;
 267}
 268
 269static spinlock_t cdev_lock = SPIN_LOCK_UNLOCKED;
 270
 271static struct kobject *cdev_get(struct cdev *p)
 272{
 273        struct module *owner = p->owner;
 274        struct kobject *kobj;
 275
 276        if (owner && !try_module_get(owner))
 277                return NULL;
 278        kobj = kobject_get(&p->kobj);
 279        if (!kobj)
 280                module_put(owner);
 281        return kobj;
 282}
 283
 284void cdev_put(struct cdev *p)
 285{
 286        if (p) {
 287                struct module *owner = p->owner;
 288                kobject_put(&p->kobj);
 289                module_put(owner);
 290        }
 291}
 292
 293/*
 294 * Called every time a character special file is opened
 295 */
 296int chrdev_open(struct inode * inode, struct file * filp)
 297{
 298        struct cdev *p;
 299        struct cdev *new = NULL;
 300        int ret = 0;
 301
 302        spin_lock(&cdev_lock);
 303        p = inode->i_cdev;
 304        if (!p) {
 305                struct kobject *kobj;
 306                int idx;
 307                spin_unlock(&cdev_lock);
 308                kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
 309                if (!kobj)
 310                        return -ENXIO;
 311                new = container_of(kobj, struct cdev, kobj);
 312                spin_lock(&cdev_lock);
 313                p = inode->i_cdev;
 314                if (!p) {
 315                        inode->i_cdev = p = new;
 316                        inode->i_cindex = idx;
 317                        list_add(&inode->i_devices, &p->list);
 318                        new = NULL;
 319                } else if (!cdev_get(p))
 320                        ret = -ENXIO;
 321        } else if (!cdev_get(p))
 322                ret = -ENXIO;
 323        spin_unlock(&cdev_lock);
 324        cdev_put(new);
 325        if (ret)
 326                return ret;
 327        filp->f_op = fops_get(p->ops);
 328        if (!filp->f_op) {
 329                cdev_put(p);
 330                return -ENXIO;
 331        }
 332        if (filp->f_op->open) {
 333                lock_kernel();
 334                ret = filp->f_op->open(inode,filp);
 335                unlock_kernel();
 336        }
 337        if (ret)
 338                cdev_put(p);
 339        return ret;
 340}
 341
 342void cd_forget(struct inode *inode)
 343{
 344        spin_lock(&cdev_lock);
 345        list_del_init(&inode->i_devices);
 346        inode->i_cdev = NULL;
 347        spin_unlock(&cdev_lock);
 348}
 349
 350void cdev_purge(struct cdev *cdev)
 351{
 352        spin_lock(&cdev_lock);
 353        while (!list_empty(&cdev->list)) {
 354                struct inode *inode;
 355                inode = container_of(cdev->list.next, struct inode, i_devices);
 356                list_del_init(&inode->i_devices);
 357                inode->i_cdev = NULL;
 358        }
 359        spin_unlock(&cdev_lock);
 360}
 361
 362/*
 363 * Dummy default file-operations: the only thing this does
 364 * is contain the open that then fills in the correct operations
 365 * depending on the special file...
 366 */
 367struct file_operations def_chr_fops = {
 368        .open = chrdev_open,
 369};
 370
 371static struct kobject *exact_match(dev_t dev, int *part, void *data)
 372{
 373        struct cdev *p = data;
 374        return &p->kobj;
 375}
 376
 377static int exact_lock(dev_t dev, void *data)
 378{
 379        struct cdev *p = data;
 380        return cdev_get(p) ? 0 : -1;
 381}
 382
 383int cdev_add(struct cdev *p, dev_t dev, unsigned count)
 384{
 385        p->dev = dev;
 386        p->count = count;
 387        return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
 388}
 389
 390static void cdev_unmap(dev_t dev, unsigned count)
 391{
 392        kobj_unmap(cdev_map, dev, count);
 393}
 394
 395void cdev_del(struct cdev *p)
 396{
 397        cdev_unmap(p->dev, p->count);
 398        kobject_put(&p->kobj);
 399}
 400
 401
 402static decl_subsys(cdev, NULL, NULL);
 403
 404static void cdev_default_release(struct kobject *kobj)
 405{
 406        struct cdev *p = container_of(kobj, struct cdev, kobj);
 407        cdev_purge(p);
 408}
 409
 410static void cdev_dynamic_release(struct kobject *kobj)
 411{
 412        struct cdev *p = container_of(kobj, struct cdev, kobj);
 413        cdev_purge(p);
 414        kfree(p);
 415}
 416
 417static struct kobj_type ktype_cdev_default = {
 418        .release        = cdev_default_release,
 419};
 420
 421static struct kobj_type ktype_cdev_dynamic = {
 422        .release        = cdev_dynamic_release,
 423};
 424
 425struct cdev *cdev_alloc(void)
 426{
 427        struct cdev *p = kmalloc(sizeof(struct cdev), GFP_KERNEL);
 428        if (p) {
 429                memset(p, 0, sizeof(struct cdev));
 430                p->kobj.ktype = &ktype_cdev_dynamic;
 431                INIT_LIST_HEAD(&p->list);
 432                kobject_init(&p->kobj);
 433        }
 434        return p;
 435}
 436
 437void cdev_init(struct cdev *cdev, struct file_operations *fops)
 438{
 439        INIT_LIST_HEAD(&cdev->list);
 440        cdev->kobj.ktype = &ktype_cdev_default;
 441        kobject_init(&cdev->kobj);
 442        cdev->ops = fops;
 443}
 444
 445static struct kobject *base_probe(dev_t dev, int *part, void *data)
 446{
 447        if (request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0)
 448                /* Make old-style 2.4 aliases work */
 449                request_module("char-major-%d", MAJOR(dev));
 450        return NULL;
 451}
 452
 453void __init chrdev_init(void)
 454{
 455/*
 456 * Keep cdev_subsys around because (and only because) the kobj_map code
 457 * depends on the rwsem it contains.  We don't make it public in sysfs,
 458 * however.
 459 */
 460        subsystem_init(&cdev_subsys);
 461        cdev_map = kobj_map_init(base_probe, &cdev_subsys);
 462}
 463
 464
 465/* Let modules do char dev stuff */
 466EXPORT_SYMBOL(register_chrdev_region);
 467EXPORT_SYMBOL(unregister_chrdev_region);
 468EXPORT_SYMBOL(alloc_chrdev_region);
 469EXPORT_SYMBOL(cdev_init);
 470EXPORT_SYMBOL(cdev_alloc);
 471EXPORT_SYMBOL(cdev_del);
 472EXPORT_SYMBOL(cdev_add);
 473EXPORT_SYMBOL(register_chrdev);
 474EXPORT_SYMBOL(unregister_chrdev);
 475