linux/drivers/s390/char/tape_class.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright IBM Corp. 2004
   3 * tape_class.c
   4 *
   5 * Tape class device support
   6 *
   7 * Author: Stefan Bader <shbader@de.ibm.com>
   8 * Based on simple class device code by Greg K-H
   9 */
  10#include "tape_class.h"
  11
  12MODULE_AUTHOR("Stefan Bader <shbader@de.ibm.com>");
  13MODULE_DESCRIPTION(
  14        "(C) Copyright IBM Corp. 2004   All Rights Reserved.\n"
  15        "tape_class.c"
  16);
  17MODULE_LICENSE("GPL");
  18
  19static struct class *tape_class;
  20
  21/*
  22 * Register a tape device and return a pointer to the cdev structure.
  23 *
  24 * device
  25 *      The pointer to the struct device of the physical (base) device.
  26 * drivername
  27 *      The pointer to the drivers name for it's character devices.
  28 * dev
  29 *      The intended major/minor number. The major number may be 0 to
  30 *      get a dynamic major number.
  31 * fops
  32 *      The pointer to the drivers file operations for the tape device.
  33 * devname
  34 *      The pointer to the name of the character device.
  35 */
  36struct tape_class_device *register_tape_dev(
  37        struct device *         device,
  38        dev_t                   dev,
  39        const struct file_operations *fops,
  40        char *                  device_name,
  41        char *                  mode_name)
  42{
  43        struct tape_class_device *      tcd;
  44        int             rc;
  45        char *          s;
  46
  47        tcd = kzalloc(sizeof(struct tape_class_device), GFP_KERNEL);
  48        if (!tcd)
  49                return ERR_PTR(-ENOMEM);
  50
  51        strncpy(tcd->device_name, device_name, TAPECLASS_NAME_LEN);
  52        for (s = strchr(tcd->device_name, '/'); s; s = strchr(s, '/'))
  53                *s = '!';
  54        strncpy(tcd->mode_name, mode_name, TAPECLASS_NAME_LEN);
  55        for (s = strchr(tcd->mode_name, '/'); s; s = strchr(s, '/'))
  56                *s = '!';
  57
  58        tcd->char_device = cdev_alloc();
  59        if (!tcd->char_device) {
  60                rc = -ENOMEM;
  61                goto fail_with_tcd;
  62        }
  63
  64        tcd->char_device->owner = fops->owner;
  65        tcd->char_device->ops   = fops;
  66        tcd->char_device->dev   = dev;
  67
  68        rc = cdev_add(tcd->char_device, tcd->char_device->dev, 1);
  69        if (rc)
  70                goto fail_with_cdev;
  71
  72        tcd->class_device = device_create(tape_class, device,
  73                                          tcd->char_device->dev, NULL,
  74                                          "%s", tcd->device_name);
  75        rc = IS_ERR(tcd->class_device) ? PTR_ERR(tcd->class_device) : 0;
  76        if (rc)
  77                goto fail_with_cdev;
  78        rc = sysfs_create_link(
  79                &device->kobj,
  80                &tcd->class_device->kobj,
  81                tcd->mode_name
  82        );
  83        if (rc)
  84                goto fail_with_class_device;
  85
  86        return tcd;
  87
  88fail_with_class_device:
  89        device_destroy(tape_class, tcd->char_device->dev);
  90
  91fail_with_cdev:
  92        cdev_del(tcd->char_device);
  93
  94fail_with_tcd:
  95        kfree(tcd);
  96
  97        return ERR_PTR(rc);
  98}
  99EXPORT_SYMBOL(register_tape_dev);
 100
 101void unregister_tape_dev(struct device *device, struct tape_class_device *tcd)
 102{
 103        if (tcd != NULL && !IS_ERR(tcd)) {
 104                sysfs_remove_link(&device->kobj, tcd->mode_name);
 105                device_destroy(tape_class, tcd->char_device->dev);
 106                cdev_del(tcd->char_device);
 107                kfree(tcd);
 108        }
 109}
 110EXPORT_SYMBOL(unregister_tape_dev);
 111
 112
 113static int __init tape_init(void)
 114{
 115        tape_class = class_create(THIS_MODULE, "tape390");
 116
 117        return 0;
 118}
 119
 120static void __exit tape_exit(void)
 121{
 122        class_destroy(tape_class);
 123        tape_class = NULL;
 124}
 125
 126postcore_initcall(tape_init);
 127module_exit(tape_exit);
 128