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