18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2004 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Tape class device support 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Stefan Bader <shbader@de.ibm.com> 88c2ecf20Sopenharmony_ci * Based on simple class device code by Greg K-H 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "tape" 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "tape_class.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stefan Bader <shbader@de.ibm.com>"); 198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION( 208c2ecf20Sopenharmony_ci "Copyright IBM Corp. 2004 All Rights Reserved.\n" 218c2ecf20Sopenharmony_ci "tape_class.c" 228c2ecf20Sopenharmony_ci); 238c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic struct class *tape_class; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * Register a tape device and return a pointer to the cdev structure. 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * device 318c2ecf20Sopenharmony_ci * The pointer to the struct device of the physical (base) device. 328c2ecf20Sopenharmony_ci * drivername 338c2ecf20Sopenharmony_ci * The pointer to the drivers name for it's character devices. 348c2ecf20Sopenharmony_ci * dev 358c2ecf20Sopenharmony_ci * The intended major/minor number. The major number may be 0 to 368c2ecf20Sopenharmony_ci * get a dynamic major number. 378c2ecf20Sopenharmony_ci * fops 388c2ecf20Sopenharmony_ci * The pointer to the drivers file operations for the tape device. 398c2ecf20Sopenharmony_ci * devname 408c2ecf20Sopenharmony_ci * The pointer to the name of the character device. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cistruct tape_class_device *register_tape_dev( 438c2ecf20Sopenharmony_ci struct device * device, 448c2ecf20Sopenharmony_ci dev_t dev, 458c2ecf20Sopenharmony_ci const struct file_operations *fops, 468c2ecf20Sopenharmony_ci char * device_name, 478c2ecf20Sopenharmony_ci char * mode_name) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct tape_class_device * tcd; 508c2ecf20Sopenharmony_ci int rc; 518c2ecf20Sopenharmony_ci char * s; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci tcd = kzalloc(sizeof(struct tape_class_device), GFP_KERNEL); 548c2ecf20Sopenharmony_ci if (!tcd) 558c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci strlcpy(tcd->device_name, device_name, TAPECLASS_NAME_LEN); 588c2ecf20Sopenharmony_ci for (s = strchr(tcd->device_name, '/'); s; s = strchr(s, '/')) 598c2ecf20Sopenharmony_ci *s = '!'; 608c2ecf20Sopenharmony_ci strlcpy(tcd->mode_name, mode_name, TAPECLASS_NAME_LEN); 618c2ecf20Sopenharmony_ci for (s = strchr(tcd->mode_name, '/'); s; s = strchr(s, '/')) 628c2ecf20Sopenharmony_ci *s = '!'; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci tcd->char_device = cdev_alloc(); 658c2ecf20Sopenharmony_ci if (!tcd->char_device) { 668c2ecf20Sopenharmony_ci rc = -ENOMEM; 678c2ecf20Sopenharmony_ci goto fail_with_tcd; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci tcd->char_device->owner = fops->owner; 718c2ecf20Sopenharmony_ci tcd->char_device->ops = fops; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci rc = cdev_add(tcd->char_device, dev, 1); 748c2ecf20Sopenharmony_ci if (rc) 758c2ecf20Sopenharmony_ci goto fail_with_cdev; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci tcd->class_device = device_create(tape_class, device, 788c2ecf20Sopenharmony_ci tcd->char_device->dev, NULL, 798c2ecf20Sopenharmony_ci "%s", tcd->device_name); 808c2ecf20Sopenharmony_ci rc = PTR_ERR_OR_ZERO(tcd->class_device); 818c2ecf20Sopenharmony_ci if (rc) 828c2ecf20Sopenharmony_ci goto fail_with_cdev; 838c2ecf20Sopenharmony_ci rc = sysfs_create_link( 848c2ecf20Sopenharmony_ci &device->kobj, 858c2ecf20Sopenharmony_ci &tcd->class_device->kobj, 868c2ecf20Sopenharmony_ci tcd->mode_name 878c2ecf20Sopenharmony_ci ); 888c2ecf20Sopenharmony_ci if (rc) 898c2ecf20Sopenharmony_ci goto fail_with_class_device; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return tcd; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cifail_with_class_device: 948c2ecf20Sopenharmony_ci device_destroy(tape_class, tcd->char_device->dev); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cifail_with_cdev: 978c2ecf20Sopenharmony_ci cdev_del(tcd->char_device); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cifail_with_tcd: 1008c2ecf20Sopenharmony_ci kfree(tcd); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return ERR_PTR(rc); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(register_tape_dev); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_civoid unregister_tape_dev(struct device *device, struct tape_class_device *tcd) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci if (tcd != NULL && !IS_ERR(tcd)) { 1098c2ecf20Sopenharmony_ci sysfs_remove_link(&device->kobj, tcd->mode_name); 1108c2ecf20Sopenharmony_ci device_destroy(tape_class, tcd->char_device->dev); 1118c2ecf20Sopenharmony_ci cdev_del(tcd->char_device); 1128c2ecf20Sopenharmony_ci kfree(tcd); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(unregister_tape_dev); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int __init tape_init(void) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci tape_class = class_create(THIS_MODULE, "tape390"); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void __exit tape_exit(void) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci class_destroy(tape_class); 1288c2ecf20Sopenharmony_ci tape_class = NULL; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cipostcore_initcall(tape_init); 1328c2ecf20Sopenharmony_cimodule_exit(tape_exit); 133