5
5
#include <linux/acpi.h>
6
6
#include <linux/bits.h>
7
7
#include <linux/init.h>
8
+ #include <linux/kdev_t.h>
8
9
#include <linux/mutex.h>
9
10
#include <linux/platform_profile.h>
10
11
#include <linux/sysfs.h>
@@ -22,6 +23,12 @@ static const char * const profile_names[] = {
22
23
};
23
24
static_assert (ARRAY_SIZE (profile_names ) == PLATFORM_PROFILE_LAST );
24
25
26
+ static DEFINE_IDA (platform_profile_ida );
27
+
28
+ static const struct class platform_profile_class = {
29
+ .name = "platform-profile" ,
30
+ };
31
+
25
32
static ssize_t platform_profile_choices_show (struct device * dev ,
26
33
struct device_attribute * attr ,
27
34
char * buf )
@@ -101,8 +108,21 @@ static struct attribute *platform_profile_attrs[] = {
101
108
NULL
102
109
};
103
110
111
+ static int profile_class_registered (struct device * dev , const void * data )
112
+ {
113
+ return 1 ;
114
+ }
115
+
116
+ static umode_t profile_class_is_visible (struct kobject * kobj , struct attribute * attr , int idx )
117
+ {
118
+ if (!class_find_device (& platform_profile_class , NULL , NULL , profile_class_registered ))
119
+ return 0 ;
120
+ return attr -> mode ;
121
+ }
122
+
104
123
static const struct attribute_group platform_profile_group = {
105
- .attrs = platform_profile_attrs
124
+ .attrs = platform_profile_attrs ,
125
+ .is_visible = profile_class_is_visible ,
106
126
};
107
127
108
128
void platform_profile_notify (struct platform_profile_handler * pprof )
@@ -160,25 +180,77 @@ int platform_profile_register(struct platform_profile_handler *pprof)
160
180
if (cur_profile )
161
181
return - EEXIST ;
162
182
163
- err = sysfs_create_group (acpi_kobj , & platform_profile_group );
164
- if (err )
165
- return err ;
183
+ /* create class interface for individual handler */
184
+ pprof -> minor = ida_alloc (& platform_profile_ida , GFP_KERNEL );
185
+ if (pprof -> minor < 0 )
186
+ return pprof -> minor ;
187
+ pprof -> class_dev = device_create (& platform_profile_class , pprof -> dev ,
188
+ MKDEV (0 , 0 ), pprof , "platform-profile-%d" ,
189
+ pprof -> minor );
190
+ if (IS_ERR (pprof -> class_dev )) {
191
+ err = PTR_ERR (pprof -> class_dev );
192
+ goto cleanup_ida ;
193
+ }
166
194
167
195
cur_profile = pprof ;
196
+
197
+ err = sysfs_update_group (acpi_kobj , & platform_profile_group );
198
+ if (err )
199
+ goto cleanup_cur ;
200
+
168
201
return 0 ;
202
+
203
+ cleanup_cur :
204
+ cur_profile = NULL ;
205
+ device_unregister (pprof -> class_dev );
206
+
207
+ cleanup_ida :
208
+ ida_free (& platform_profile_ida , pprof -> minor );
209
+
210
+ return err ;
169
211
}
170
212
EXPORT_SYMBOL_GPL (platform_profile_register );
171
213
172
214
int platform_profile_remove (struct platform_profile_handler * pprof )
173
215
{
216
+ int id ;
174
217
guard (mutex )(& profile_lock );
175
218
176
- sysfs_remove_group (acpi_kobj , & platform_profile_group );
177
219
cur_profile = NULL ;
220
+
221
+ id = pprof -> minor ;
222
+ device_unregister (pprof -> class_dev );
223
+ ida_free (& platform_profile_ida , id );
224
+
225
+ sysfs_update_group (acpi_kobj , & platform_profile_group );
226
+
178
227
return 0 ;
179
228
}
180
229
EXPORT_SYMBOL_GPL (platform_profile_remove );
181
230
231
+ static int __init platform_profile_init (void )
232
+ {
233
+ int err ;
234
+
235
+ err = class_register (& platform_profile_class );
236
+ if (err )
237
+ return err ;
238
+
239
+ err = sysfs_create_group (acpi_kobj , & platform_profile_group );
240
+ if (err )
241
+ class_unregister (& platform_profile_class );
242
+
243
+ return err ;
244
+ }
245
+
246
+ static void __exit platform_profile_exit (void )
247
+ {
248
+ sysfs_remove_group (acpi_kobj , & platform_profile_group );
249
+ class_unregister (& platform_profile_class );
250
+ }
251
+ module_init (platform_profile_init );
252
+ module_exit (platform_profile_exit );
253
+
182
254
MODULE_AUTHOR (
"Mark Pearson <[email protected] >" );
183
255
MODULE_DESCRIPTION ("ACPI platform profile sysfs interface" );
184
256
MODULE_LICENSE ("GPL" );
0 commit comments