Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * (C) Copyright IBM Corp. 2004 | |
e018ba1f | 3 | * tape_class.c |
1da177e4 LT |
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" | |
e018ba1f | 15 | "tape_class.c" |
1da177e4 LT |
16 | ); |
17 | MODULE_LICENSE("GPL"); | |
18 | ||
56b22935 | 19 | static struct class *tape_class; |
1da177e4 LT |
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, | |
9c2e08c5 | 39 | const struct file_operations *fops, |
1da177e4 LT |
40 | char * device_name, |
41 | char * mode_name) | |
42 | { | |
43 | struct tape_class_device * tcd; | |
44 | int rc; | |
45 | char * s; | |
46 | ||
88abaab4 | 47 | tcd = kzalloc(sizeof(struct tape_class_device), GFP_KERNEL); |
1da177e4 LT |
48 | if (!tcd) |
49 | return ERR_PTR(-ENOMEM); | |
50 | ||
1da177e4 LT |
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 | ||
ea9e42f6 GKH |
72 | tcd->class_device = device_create(tape_class, device, |
73 | tcd->char_device->dev, NULL, | |
74 | "%s", tcd->device_name); | |
25a2001a | 75 | rc = IS_ERR(tcd->class_device) ? PTR_ERR(tcd->class_device) : 0; |
d7cf0d57 HC |
76 | if (rc) |
77 | goto fail_with_cdev; | |
78 | rc = sysfs_create_link( | |
1da177e4 LT |
79 | &device->kobj, |
80 | &tcd->class_device->kobj, | |
81 | tcd->mode_name | |
82 | ); | |
d7cf0d57 HC |
83 | if (rc) |
84 | goto fail_with_class_device; | |
1da177e4 LT |
85 | |
86 | return tcd; | |
87 | ||
d7cf0d57 | 88 | fail_with_class_device: |
7f021ce1 | 89 | device_destroy(tape_class, tcd->char_device->dev); |
d7cf0d57 | 90 | |
1da177e4 LT |
91 | fail_with_cdev: |
92 | cdev_del(tcd->char_device); | |
93 | ||
94 | fail_with_tcd: | |
95 | kfree(tcd); | |
96 | ||
97 | return ERR_PTR(rc); | |
98 | } | |
99 | EXPORT_SYMBOL(register_tape_dev); | |
100 | ||
92bf435f | 101 | void unregister_tape_dev(struct device *device, struct tape_class_device *tcd) |
1da177e4 LT |
102 | { |
103 | if (tcd != NULL && !IS_ERR(tcd)) { | |
92bf435f | 104 | sysfs_remove_link(&device->kobj, tcd->mode_name); |
7f021ce1 | 105 | device_destroy(tape_class, tcd->char_device->dev); |
1da177e4 LT |
106 | cdev_del(tcd->char_device); |
107 | kfree(tcd); | |
108 | } | |
109 | } | |
110 | EXPORT_SYMBOL(unregister_tape_dev); | |
111 | ||
112 | ||
113 | static int __init tape_init(void) | |
114 | { | |
56b22935 | 115 | tape_class = class_create(THIS_MODULE, "tape390"); |
1da177e4 LT |
116 | |
117 | return 0; | |
118 | } | |
119 | ||
120 | static void __exit tape_exit(void) | |
121 | { | |
56b22935 | 122 | class_destroy(tape_class); |
1da177e4 LT |
123 | tape_class = NULL; |
124 | } | |
125 | ||
126 | postcore_initcall(tape_init); | |
127 | module_exit(tape_exit); |