| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * (C) Copyright IBM Corp. 2004 | 
|  | 3 | * tape_class.c ($Revision: 1.8 $) | 
|  | 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 |  | 
|  | 12 | MODULE_AUTHOR("Stefan Bader <shbader@de.ibm.com>"); | 
|  | 13 | MODULE_DESCRIPTION( | 
|  | 14 | "(C) Copyright IBM Corp. 2004   All Rights Reserved.\n" | 
|  | 15 | "tape_class.c ($Revision: 1.8 $)" | 
|  | 16 | ); | 
|  | 17 | MODULE_LICENSE("GPL"); | 
|  | 18 |  | 
| gregkh@suse.de | 56b2293 | 2005-03-23 10:01:41 -0800 | [diff] [blame] | 19 | static struct class *tape_class; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | */ | 
|  | 36 | struct tape_class_device *register_tape_dev( | 
|  | 37 | struct device *		device, | 
|  | 38 | dev_t			dev, | 
|  | 39 | 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 = kmalloc(sizeof(struct tape_class_device), GFP_KERNEL); | 
|  | 48 | if (!tcd) | 
|  | 49 | return ERR_PTR(-ENOMEM); | 
|  | 50 |  | 
|  | 51 | memset(tcd, 0, sizeof(struct tape_class_device)); | 
|  | 52 | strncpy(tcd->device_name, device_name, TAPECLASS_NAME_LEN); | 
|  | 53 | for (s = strchr(tcd->device_name, '/'); s; s = strchr(s, '/')) | 
|  | 54 | *s = '!'; | 
|  | 55 | strncpy(tcd->mode_name, mode_name, TAPECLASS_NAME_LEN); | 
|  | 56 | for (s = strchr(tcd->mode_name, '/'); s; s = strchr(s, '/')) | 
|  | 57 | *s = '!'; | 
|  | 58 |  | 
|  | 59 | tcd->char_device = cdev_alloc(); | 
|  | 60 | if (!tcd->char_device) { | 
|  | 61 | rc = -ENOMEM; | 
|  | 62 | goto fail_with_tcd; | 
|  | 63 | } | 
|  | 64 |  | 
|  | 65 | tcd->char_device->owner = fops->owner; | 
|  | 66 | tcd->char_device->ops   = fops; | 
|  | 67 | tcd->char_device->dev   = dev; | 
|  | 68 |  | 
|  | 69 | rc = cdev_add(tcd->char_device, tcd->char_device->dev, 1); | 
|  | 70 | if (rc) | 
|  | 71 | goto fail_with_cdev; | 
|  | 72 |  | 
| gregkh@suse.de | 56b2293 | 2005-03-23 10:01:41 -0800 | [diff] [blame] | 73 | tcd->class_device = class_device_create( | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | tape_class, | 
|  | 75 | tcd->char_device->dev, | 
|  | 76 | device, | 
|  | 77 | "%s", tcd->device_name | 
|  | 78 | ); | 
|  | 79 | sysfs_create_link( | 
|  | 80 | &device->kobj, | 
|  | 81 | &tcd->class_device->kobj, | 
|  | 82 | tcd->mode_name | 
|  | 83 | ); | 
|  | 84 |  | 
|  | 85 | return tcd; | 
|  | 86 |  | 
|  | 87 | fail_with_cdev: | 
|  | 88 | cdev_del(tcd->char_device); | 
|  | 89 |  | 
|  | 90 | fail_with_tcd: | 
|  | 91 | kfree(tcd); | 
|  | 92 |  | 
|  | 93 | return ERR_PTR(rc); | 
|  | 94 | } | 
|  | 95 | EXPORT_SYMBOL(register_tape_dev); | 
|  | 96 |  | 
|  | 97 | void unregister_tape_dev(struct tape_class_device *tcd) | 
|  | 98 | { | 
|  | 99 | if (tcd != NULL && !IS_ERR(tcd)) { | 
|  | 100 | sysfs_remove_link( | 
|  | 101 | &tcd->class_device->dev->kobj, | 
|  | 102 | tcd->mode_name | 
|  | 103 | ); | 
| gregkh@suse.de | 56b2293 | 2005-03-23 10:01:41 -0800 | [diff] [blame] | 104 | class_device_destroy(tape_class, tcd->char_device->dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | cdev_del(tcd->char_device); | 
|  | 106 | kfree(tcd); | 
|  | 107 | } | 
|  | 108 | } | 
|  | 109 | EXPORT_SYMBOL(unregister_tape_dev); | 
|  | 110 |  | 
|  | 111 |  | 
|  | 112 | static int __init tape_init(void) | 
|  | 113 | { | 
| gregkh@suse.de | 56b2293 | 2005-03-23 10:01:41 -0800 | [diff] [blame] | 114 | tape_class = class_create(THIS_MODULE, "tape390"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 |  | 
|  | 116 | return 0; | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | static void __exit tape_exit(void) | 
|  | 120 | { | 
| gregkh@suse.de | 56b2293 | 2005-03-23 10:01:41 -0800 | [diff] [blame] | 121 | class_destroy(tape_class); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | tape_class = NULL; | 
|  | 123 | } | 
|  | 124 |  | 
|  | 125 | postcore_initcall(tape_init); | 
|  | 126 | module_exit(tape_exit); |