Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
462 giacomo 1
/*
2
 * class.c - basic device class management
3
 *
4
 * Copyright (c) 2002-3 Patrick Mochel
5
 * Copyright (c) 2002-3 Open Source Development Labs
6
 * Copyright (c) 2003 Greg Kroah-Hartman
7
 * Copyright (c) 2003 IBM Corp.
8
 *
9
 * This file is released under the GPLv2
10
 *
11
 */
12
 
13
#undef DEBUG
14
 
15
#include <linuxcomp.h>
16
 
17
#include <linux/device.h>
18
#include <linux/module.h>
19
#include <linux/init.h>
20
#include <linux/string.h>
21
#include "base.h"
22
 
23
#define to_class_attr(_attr) container_of(_attr,struct class_attribute,attr)
24
#define to_class(obj) container_of(obj,struct class,subsys.kset.kobj)
25
 
26
static ssize_t
27
class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
28
{
29
        struct class_attribute * class_attr = to_class_attr(attr);
30
        struct class * dc = to_class(kobj);
31
        ssize_t ret = 0;
32
 
33
        if (class_attr->show)
34
                ret = class_attr->show(dc,buf);
35
        return ret;
36
}
37
 
38
static ssize_t
39
class_attr_store(struct kobject * kobj, struct attribute * attr,
40
                 const char * buf, size_t count)
41
{
42
        struct class_attribute * class_attr = to_class_attr(attr);
43
        struct class * dc = to_class(kobj);
44
        ssize_t ret = 0;
45
 
46
        if (class_attr->store)
47
                ret = class_attr->store(dc,buf,count);
48
        return ret;
49
}
50
 
51
static struct sysfs_ops class_sysfs_ops = {
52
        .show   = class_attr_show,
53
        .store  = class_attr_store,
54
};
55
 
56
static struct kobj_type ktype_class = {
57
        .sysfs_ops      = &class_sysfs_ops,
58
};
59
 
60
/* Hotplug events for classes go to the class_obj subsys */
61
static decl_subsys(class,&ktype_class,NULL);
62
 
63
 
64
int class_create_file(struct class * cls, const struct class_attribute * attr)
65
{
66
        int error;
67
        if (cls) {
68
                error = 0;//sysfs_create_file(&cls->subsys.kset.kobj,&attr->attr);
69
        } else
70
                error = -EINVAL;
71
        return error;
72
}
73
 
74
void class_remove_file(struct class * cls, const struct class_attribute * attr)
75
{
76
        //if (cls)
77
        //      sysfs_remove_file(&cls->subsys.kset.kobj,&attr->attr);
78
}
79
 
80
struct class * class_get(struct class * cls)
81
{
82
        if (cls)
83
                return container_of(subsys_get(&cls->subsys),struct class,subsys);
84
        return NULL;
85
}
86
 
87
void class_put(struct class * cls)
88
{
89
        subsys_put(&cls->subsys);
90
}
91
 
92
int class_register(struct class * cls)
93
{
94
        pr_debug("device class '%s': registering\n",cls->name);
95
 
96
        INIT_LIST_HEAD(&cls->children);
97
        INIT_LIST_HEAD(&cls->interfaces);
98
        kobject_set_name(&cls->subsys.kset.kobj,cls->name);
99
        subsys_set_kset(cls,class_subsys);
100
        subsystem_register(&cls->subsys);
101
 
102
        return 0;
103
}
104
 
105
void class_unregister(struct class * cls)
106
{
107
        pr_debug("device class '%s': unregistering\n",cls->name);
108
        subsystem_unregister(&cls->subsys);
109
}
110
 
111
/* Class Device Stuff */
112
 
113
int class_device_create_file(struct class_device * class_dev,
114
                             const struct class_device_attribute * attr)
115
{
116
        int error = -EINVAL;
117
        if (class_dev)
118
                error = 0;//sysfs_create_file(&class_dev->kobj, &attr->attr);
119
        return error;
120
}
121
 
122
void class_device_remove_file(struct class_device * class_dev,
123
                              const struct class_device_attribute * attr)
124
{
125
        //if (class_dev)
126
        //      sysfs_remove_file(&class_dev->kobj, &attr->attr);
127
}
128
 
129
static int class_device_dev_link(struct class_device * class_dev)
130
{
131
        //if (class_dev->dev)
132
        //      return sysfs_create_link(&class_dev->kobj,
133
        //                               &class_dev->dev->kobj, "device");
134
        return 0;
135
}
136
 
137
static void class_device_dev_unlink(struct class_device * class_dev)
138
{
139
        //if (class_dev->dev)
140
        //      sysfs_remove_link(&class_dev->kobj, "device");
141
}
142
 
143
static int class_device_driver_link(struct class_device * class_dev)
144
{
145
        //if ((class_dev->dev) && (class_dev->dev->driver))
146
        //      return sysfs_create_link(&class_dev->kobj,
147
        //                               &class_dev->dev->driver->kobj, "driver");
148
        return 0;
149
}
150
 
151
static void class_device_driver_unlink(struct class_device * class_dev)
152
{
153
        //if ((class_dev->dev) && (class_dev->dev->driver))
154
        //      sysfs_remove_link(&class_dev->kobj, "driver");
155
}
156
 
157
 
158
static ssize_t
159
class_device_attr_show(struct kobject * kobj, struct attribute * attr,
160
                       char * buf)
161
{
162
        struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
163
        struct class_device * cd = to_class_dev(kobj);
164
        ssize_t ret = 0;
165
 
166
        if (class_dev_attr->show)
167
                ret = class_dev_attr->show(cd,buf);
168
        return ret;
169
}
170
 
171
static ssize_t
172
class_device_attr_store(struct kobject * kobj, struct attribute * attr,
173
                        const char * buf, size_t count)
174
{
175
        struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
176
        struct class_device * cd = to_class_dev(kobj);
177
        ssize_t ret = 0;
178
 
179
        if (class_dev_attr->store)
180
                ret = class_dev_attr->store(cd,buf,count);
181
        return ret;
182
}
183
 
184
static struct sysfs_ops class_dev_sysfs_ops = {
185
        .show   = class_device_attr_show,
186
        .store  = class_device_attr_store,
187
};
188
 
189
static void class_dev_release(struct kobject * kobj)
190
{
191
        struct class_device *cd = to_class_dev(kobj);
192
        struct class * cls = cd->class;
193
 
194
        pr_debug("device class '%s': release.\n",cd->class_id);
195
 
196
        if (cls->release)
197
                cls->release(cd);
198
        else {
199
                printk(KERN_ERR "Device class '%s' does not have a release() function, "
200
                        "it is broken and must be fixed.\n",
201
                        cd->class_id);
202
                WARN_ON(1);
203
        }
204
}
205
 
206
static struct kobj_type ktype_class_device = {
207
        .sysfs_ops      = &class_dev_sysfs_ops,
208
        .release        = class_dev_release,
209
};
210
 
211
static int class_hotplug_filter(struct kset *kset, struct kobject *kobj)
212
{
213
        struct kobj_type *ktype = get_ktype(kobj);
214
 
215
        if (ktype == &ktype_class_device) {
216
                struct class_device *class_dev = to_class_dev(kobj);
217
                if (class_dev->class)
218
                        return 1;
219
        }
220
        return 0;
221
}
222
 
223
static char *class_hotplug_name(struct kset *kset, struct kobject *kobj)
224
{
225
        struct class_device *class_dev = to_class_dev(kobj);
226
 
227
        return class_dev->class->name;
228
}
229
 
230
static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
231
                         int num_envp, char *buffer, int buffer_size)
232
{
233
        struct class_device *class_dev = to_class_dev(kobj);
234
        int retval = 0;
235
 
236
        pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
237
        if (class_dev->class->hotplug) {
238
                /* have the bus specific function add its stuff */
239
                retval = class_dev->class->hotplug (class_dev, envp, num_envp,
240
                                                    buffer, buffer_size);
241
                        if (retval) {
242
                        pr_debug ("%s - hotplug() returned %d\n",
243
                                  __FUNCTION__, retval);
244
                }
245
        }
246
 
247
        return retval;
248
}
249
 
250
static struct kset_hotplug_ops class_hotplug_ops = {
251
        .filter =       class_hotplug_filter,
252
        .name =         class_hotplug_name,
253
        .hotplug =      class_hotplug,
254
};
255
 
256
static decl_subsys(class_obj, &ktype_class_device, &class_hotplug_ops);
257
 
258
void class_device_initialize(struct class_device *class_dev)
259
{
260
        kobj_set_kset_s(class_dev, class_obj_subsys);
261
        kobject_init(&class_dev->kobj);
262
        INIT_LIST_HEAD(&class_dev->node);
263
}
264
 
265
int class_device_add(struct class_device *class_dev)
266
{
267
        struct class * parent;
268
        struct class_interface * class_intf;
269
        struct list_head * entry;
270
        int error;
271
 
272
        class_dev = class_device_get(class_dev);
273
        if (!class_dev || !strlen(class_dev->class_id))
274
                return -EINVAL;
275
 
276
        parent = class_get(class_dev->class);
277
 
278
        pr_debug("CLASS: registering class device: ID = '%s'\n",
279
                 class_dev->class_id);
280
 
281
        /* first, register with generic layer. */
282
        kobject_set_name(&class_dev->kobj, class_dev->class_id);
283
        if (parent)
284
                class_dev->kobj.parent = &parent->subsys.kset.kobj;
285
 
286
        if ((error = kobject_add(&class_dev->kobj)))
287
                goto register_done;
288
 
289
        /* now take care of our own registration */
290
        if (parent) {
291
                //down_write(&parent->subsys.rwsem);
292
                list_add_tail(&class_dev->node, &parent->children);
293
                list_for_each(entry, &parent->interfaces) {
294
                        class_intf = container_of(entry, struct class_interface, node);
295
                        if (class_intf->add)
296
                                class_intf->add(class_dev);
297
                }
298
                //up_write(&parent->subsys.rwsem);
299
        }
300
 
301
        class_device_dev_link(class_dev);
302
        class_device_driver_link(class_dev);
303
 
304
 register_done:
305
        if (error && parent)
306
                class_put(parent);
307
        class_device_put(class_dev);
308
        return error;
309
}
310
 
311
int class_device_register(struct class_device *class_dev)
312
{
313
        class_device_initialize(class_dev);
314
        return class_device_add(class_dev);
315
}
316
 
317
void class_device_del(struct class_device *class_dev)
318
{
319
        struct class * parent = class_dev->class;
320
        struct class_interface * class_intf;
321
        struct list_head * entry;
322
 
323
        if (parent) {
324
                //down_write(&parent->subsys.rwsem);
325
                list_del_init(&class_dev->node);
326
                list_for_each(entry, &parent->interfaces) {
327
                        class_intf = container_of(entry, struct class_interface, node);
328
                        if (class_intf->remove)
329
                                class_intf->remove(class_dev);
330
                }
331
                //up_write(&parent->subsys.rwsem);
332
        }
333
 
334
        class_device_dev_unlink(class_dev);
335
        class_device_driver_unlink(class_dev);
336
 
337
        kobject_del(&class_dev->kobj);
338
 
339
        if (parent)
340
                class_put(parent);
341
}
342
 
343
void class_device_unregister(struct class_device *class_dev)
344
{
345
        pr_debug("CLASS: Unregistering class device. ID = '%s'\n",
346
                 class_dev->class_id);
347
        class_device_del(class_dev);
348
        class_device_put(class_dev);
349
}
350
 
351
int class_device_rename(struct class_device *class_dev, char *new_name)
352
{
353
        class_dev = class_device_get(class_dev);
354
        if (!class_dev)
355
                return -EINVAL;
356
 
357
        pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id,
358
                 new_name);
359
 
360
        strncpy(class_dev->class_id, new_name, KOBJ_NAME_LEN);
361
 
362
        kobject_rename(&class_dev->kobj, new_name);
363
 
364
        class_device_put(class_dev);
365
 
366
        return 0;
367
}
368
 
369
struct class_device * class_device_get(struct class_device *class_dev)
370
{
371
        if (class_dev)
372
                return to_class_dev(kobject_get(&class_dev->kobj));
373
        return NULL;
374
}
375
 
376
void class_device_put(struct class_device *class_dev)
377
{
378
        kobject_put(&class_dev->kobj);
379
}
380
 
381
 
382
int class_interface_register(struct class_interface *class_intf)
383
{
384
        struct class * parent;
385
        struct class_device * class_dev;
386
        struct list_head * entry;
387
 
388
        if (!class_intf || !class_intf->class)
389
                return -ENODEV;
390
 
391
        parent = class_get(class_intf->class);
392
        if (!parent)
393
                return -EINVAL;
394
 
395
        //down_write(&parent->subsys.rwsem);
396
        list_add_tail(&class_intf->node, &parent->interfaces);
397
 
398
        if (class_intf->add) {
399
                list_for_each(entry, &parent->children) {
400
                        class_dev = container_of(entry, struct class_device, node);
401
                        class_intf->add(class_dev);
402
                }
403
        }
404
        //up_write(&parent->subsys.rwsem);
405
 
406
        return 0;
407
}
408
 
409
void class_interface_unregister(struct class_interface *class_intf)
410
{
411
        struct class * parent = class_intf->class;
412
        struct list_head * entry;
413
 
414
        if (!parent)
415
                return;
416
 
417
        //down_write(&parent->subsys.rwsem);
418
        list_del_init(&class_intf->node);
419
 
420
        if (class_intf->remove) {
421
                list_for_each(entry, &parent->children) {
422
                        struct class_device *class_dev = container_of(entry, struct class_device, node);
423
                        class_intf->remove(class_dev);
424
                }
425
        }
426
        //up_write(&parent->subsys.rwsem);
427
 
428
        class_put(parent);
429
}
430
 
431
 
432
 
433
int __init classes_init(void)
434
{
435
        int retval;
436
 
437
        retval = subsystem_register(&class_subsys);
438
        if (retval)
439
                return retval;
440
 
441
        /* ick, this is ugly, the things we go through to keep from showing up
442
         * in sysfs... */
443
        subsystem_init(&class_obj_subsys);
444
        if (!class_obj_subsys.kset.subsys)
445
                        class_obj_subsys.kset.subsys = &class_obj_subsys;
446
        return 0;
447
}
448
 
449
EXPORT_SYMBOL(class_create_file);
450
EXPORT_SYMBOL(class_remove_file);
451
EXPORT_SYMBOL(class_register);
452
EXPORT_SYMBOL(class_unregister);
453
EXPORT_SYMBOL(class_get);
454
EXPORT_SYMBOL(class_put);
455
 
456
EXPORT_SYMBOL(class_device_register);
457
EXPORT_SYMBOL(class_device_unregister);
458
EXPORT_SYMBOL(class_device_initialize);
459
EXPORT_SYMBOL(class_device_add);
460
EXPORT_SYMBOL(class_device_del);
461
EXPORT_SYMBOL(class_device_get);
462
EXPORT_SYMBOL(class_device_put);
463
EXPORT_SYMBOL(class_device_create_file);
464
EXPORT_SYMBOL(class_device_remove_file);
465
 
466
EXPORT_SYMBOL(class_interface_register);
467
EXPORT_SYMBOL(class_interface_unregister);