Blame view
drivers/base/sys.c
9.65 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * sys.c - pseudo-bus for system 'devices' (cpus, PICs, timers, etc) * * Copyright (c) 2002-3 Patrick Mochel * 2002-3 Open Source Development Lab * * This file is released under the GPLv2 * * This exports a 'system' bus type. * By default, a 'sys' bus gets added to the root of the system. There will * always be core system devices. Devices can use sysdev_register() to * add themselves as children of the system bus. */ |
1da177e4c Linux-2.6.12-rc2 |
14 15 16 17 18 |
#include <linux/sysdev.h> #include <linux/err.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> |
1da177e4c Linux-2.6.12-rc2 |
19 |
#include <linux/string.h> |
438510f6f [PATCH] pm_messag... |
20 |
#include <linux/pm.h> |
f67d115fe [PATCH] drivers/b... |
21 |
#include <linux/device.h> |
9f3f776bd sysdev: use mutex... |
22 |
#include <linux/mutex.h> |
2ed8d2b3a PM: Rework handli... |
23 |
#include <linux/interrupt.h> |
1da177e4c Linux-2.6.12-rc2 |
24 |
|
f67d115fe [PATCH] drivers/b... |
25 |
#include "base.h" |
1da177e4c Linux-2.6.12-rc2 |
26 27 28 29 30 |
#define to_sysdev(k) container_of(k, struct sys_device, kobj) #define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr) static ssize_t |
60530afe1 Driver core: some... |
31 |
sysdev_show(struct kobject *kobj, struct attribute *attr, char *buffer) |
1da177e4c Linux-2.6.12-rc2 |
32 |
{ |
60530afe1 Driver core: some... |
33 34 |
struct sys_device *sysdev = to_sysdev(kobj); struct sysdev_attribute *sysdev_attr = to_sysdev_attr(attr); |
1da177e4c Linux-2.6.12-rc2 |
35 36 |
if (sysdev_attr->show) |
4a0b2b4db sysdev: Pass the ... |
37 |
return sysdev_attr->show(sysdev, sysdev_attr, buffer); |
4a0c20bf8 [PATCH] sysfs: (d... |
38 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
39 40 41 42 |
} static ssize_t |
60530afe1 Driver core: some... |
43 44 |
sysdev_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) |
1da177e4c Linux-2.6.12-rc2 |
45 |
{ |
60530afe1 Driver core: some... |
46 47 |
struct sys_device *sysdev = to_sysdev(kobj); struct sysdev_attribute *sysdev_attr = to_sysdev_attr(attr); |
1da177e4c Linux-2.6.12-rc2 |
48 49 |
if (sysdev_attr->store) |
4a0b2b4db sysdev: Pass the ... |
50 |
return sysdev_attr->store(sysdev, sysdev_attr, buffer, count); |
4a0c20bf8 [PATCH] sysfs: (d... |
51 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
52 |
} |
52cf25d0a Driver core: Cons... |
53 |
static const struct sysfs_ops sysfs_ops = { |
1da177e4c Linux-2.6.12-rc2 |
54 55 56 57 58 59 60 |
.show = sysdev_show, .store = sysdev_store, }; static struct kobj_type ktype_sysdev = { .sysfs_ops = &sysfs_ops, }; |
60530afe1 Driver core: some... |
61 |
int sysdev_create_file(struct sys_device *s, struct sysdev_attribute *a) |
1da177e4c Linux-2.6.12-rc2 |
62 63 64 |
{ return sysfs_create_file(&s->kobj, &a->attr); } |
60530afe1 Driver core: some... |
65 |
void sysdev_remove_file(struct sys_device *s, struct sysdev_attribute *a) |
1da177e4c Linux-2.6.12-rc2 |
66 67 68 69 70 71 |
{ sysfs_remove_file(&s->kobj, &a->attr); } EXPORT_SYMBOL_GPL(sysdev_create_file); EXPORT_SYMBOL_GPL(sysdev_remove_file); |
670dd90d8 [PATCH] Driver Co... |
72 73 74 75 76 77 78 |
#define to_sysdev_class(k) container_of(k, struct sysdev_class, kset.kobj) #define to_sysdev_class_attr(a) container_of(a, \ struct sysdev_class_attribute, attr) static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr, char *buffer) { |
60530afe1 Driver core: some... |
79 |
struct sysdev_class *class = to_sysdev_class(kobj); |
670dd90d8 [PATCH] Driver Co... |
80 81 82 |
struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr); if (class_attr->show) |
c9be0a36f sysdev: Pass attr... |
83 |
return class_attr->show(class, class_attr, buffer); |
670dd90d8 [PATCH] Driver Co... |
84 85 86 87 88 89 |
return -EIO; } static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { |
60530afe1 Driver core: some... |
90 91 |
struct sysdev_class *class = to_sysdev_class(kobj); struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr); |
670dd90d8 [PATCH] Driver Co... |
92 93 |
if (class_attr->store) |
c9be0a36f sysdev: Pass attr... |
94 |
return class_attr->store(class, class_attr, buffer, count); |
670dd90d8 [PATCH] Driver Co... |
95 96 |
return -EIO; } |
52cf25d0a Driver core: Cons... |
97 |
static const struct sysfs_ops sysfs_class_ops = { |
670dd90d8 [PATCH] Driver Co... |
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
.show = sysdev_class_show, .store = sysdev_class_store, }; static struct kobj_type ktype_sysdev_class = { .sysfs_ops = &sysfs_class_ops, }; int sysdev_class_create_file(struct sysdev_class *c, struct sysdev_class_attribute *a) { return sysfs_create_file(&c->kset.kobj, &a->attr); } EXPORT_SYMBOL_GPL(sysdev_class_create_file); void sysdev_class_remove_file(struct sysdev_class *c, struct sysdev_class_attribute *a) { sysfs_remove_file(&c->kset.kobj, &a->attr); } EXPORT_SYMBOL_GPL(sysdev_class_remove_file); |
ca22e56de driver-core: impl... |
119 |
extern struct kset *system_kset; |
1da177e4c Linux-2.6.12-rc2 |
120 |
|
60530afe1 Driver core: some... |
121 |
int sysdev_class_register(struct sysdev_class *cls) |
1da177e4c Linux-2.6.12-rc2 |
122 |
{ |
9227c47bb driver-core: make... |
123 |
int retval; |
838ea8e8d sysdev: fix debug... |
124 125 |
pr_debug("Registering sysdev class '%s' ", cls->name); |
1da177e4c Linux-2.6.12-rc2 |
126 |
INIT_LIST_HEAD(&cls->drivers); |
ef79df263 sysdev: fix probl... |
127 |
memset(&cls->kset.kobj, 0x00, sizeof(struct kobject)); |
aade4041a kset: convert /sy... |
128 |
cls->kset.kobj.parent = &system_kset->kobj; |
3514faca1 kobject: remove s... |
129 |
cls->kset.kobj.ktype = &ktype_sysdev_class; |
aade4041a kset: convert /sy... |
130 |
cls->kset.kobj.kset = system_kset; |
9227c47bb driver-core: make... |
131 |
|
acc0e90fb driver core: fix ... |
132 |
retval = kobject_set_name(&cls->kset.kobj, "%s", cls->name); |
9227c47bb driver-core: make... |
133 134 |
if (retval) return retval; |
38457ab3a sysfs: Add attrib... |
135 136 137 138 139 |
retval = kset_register(&cls->kset); if (!retval && cls->attrs) retval = sysfs_create_files(&cls->kset.kobj, (const struct attribute **)cls->attrs); return retval; |
1da177e4c Linux-2.6.12-rc2 |
140 |
} |
60530afe1 Driver core: some... |
141 |
void sysdev_class_unregister(struct sysdev_class *cls) |
1da177e4c Linux-2.6.12-rc2 |
142 143 144 145 |
{ pr_debug("Unregistering sysdev class '%s' ", kobject_name(&cls->kset.kobj)); |
38457ab3a sysfs: Add attrib... |
146 147 148 |
if (cls->attrs) sysfs_remove_files(&cls->kset.kobj, (const struct attribute **)cls->attrs); |
1da177e4c Linux-2.6.12-rc2 |
149 150 151 152 153 |
kset_unregister(&cls->kset); } EXPORT_SYMBOL_GPL(sysdev_class_register); EXPORT_SYMBOL_GPL(sysdev_class_unregister); |
9f3f776bd sysdev: use mutex... |
154 |
static DEFINE_MUTEX(sysdev_drivers_lock); |
1da177e4c Linux-2.6.12-rc2 |
155 |
|
f4203e303 sysdev: Do not re... |
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
/* * @dev != NULL means that we're unwinding because some drv->add() * failed for some reason. You need to grab sysdev_drivers_lock before * calling this. */ static void __sysdev_driver_remove(struct sysdev_class *cls, struct sysdev_driver *drv, struct sys_device *from_dev) { struct sys_device *dev = from_dev; list_del_init(&drv->entry); if (!cls) return; if (!drv->remove) goto kset_put; if (dev) list_for_each_entry_continue_reverse(dev, &cls->kset.list, kobj.entry) drv->remove(dev); else list_for_each_entry(dev, &cls->kset.list, kobj.entry) drv->remove(dev); kset_put: kset_put(&cls->kset); } |
1da177e4c Linux-2.6.12-rc2 |
185 |
/** |
25985edce Fix common misspe... |
186 |
* sysdev_driver_register - Register auxiliary driver |
44b760a82 sysdev: remove gl... |
187 |
* @cls: Device class driver belongs to. |
1da177e4c Linux-2.6.12-rc2 |
188 189 |
* @drv: Driver. * |
44b760a82 sysdev: remove gl... |
190 |
* @drv is inserted into @cls->drivers to be |
1da177e4c Linux-2.6.12-rc2 |
191 192 |
* called on each operation on devices of that class. The refcount * of @cls is incremented. |
1da177e4c Linux-2.6.12-rc2 |
193 |
*/ |
44b760a82 sysdev: remove gl... |
194 |
int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) |
1da177e4c Linux-2.6.12-rc2 |
195 |
{ |
f4203e303 sysdev: Do not re... |
196 |
struct sys_device *dev = NULL; |
44b760a82 sysdev: remove gl... |
197 |
int err = 0; |
da009f39f sysdev: detect mu... |
198 |
if (!cls) { |
345279bc1 sysdev: Fixup war... |
199 200 201 |
WARN(1, KERN_WARNING "sysdev: invalid class passed to %s! ", __func__); |
da009f39f sysdev: detect mu... |
202 203 204 205 |
return -EINVAL; } /* Check whether this driver has already been added to a class. */ |
f810a5cf2 Use WARN() in dri... |
206 207 |
if (drv->entry.next && !list_empty(&drv->entry)) WARN(1, KERN_WARNING "sysdev: class %s: driver (%p) has already" |
da009f39f sysdev: detect mu... |
208 209 210 |
" been registered to a class, something is wrong, but " "will forge on! ", cls->name, drv); |
da009f39f sysdev: detect mu... |
211 |
|
9f3f776bd sysdev: use mutex... |
212 |
mutex_lock(&sysdev_drivers_lock); |
1da177e4c Linux-2.6.12-rc2 |
213 214 215 216 217 |
if (cls && kset_get(&cls->kset)) { list_add_tail(&drv->entry, &cls->drivers); /* If devices of this class already exist, tell the driver */ if (drv->add) { |
f4203e303 sysdev: Do not re... |
218 219 220 221 222 |
list_for_each_entry(dev, &cls->kset.list, kobj.entry) { err = drv->add(dev); if (err) goto unwind; } |
1da177e4c Linux-2.6.12-rc2 |
223 |
} |
44b760a82 sysdev: remove gl... |
224 225 |
} else { err = -EINVAL; |
f810a5cf2 Use WARN() in dri... |
226 227 |
WARN(1, KERN_ERR "%s: invalid device class ", __func__); |
44b760a82 sysdev: remove gl... |
228 |
} |
f4203e303 sysdev: Do not re... |
229 230 231 232 233 234 235 |
goto unlock; unwind: __sysdev_driver_remove(cls, drv, dev); unlock: |
9f3f776bd sysdev: use mutex... |
236 |
mutex_unlock(&sysdev_drivers_lock); |
44b760a82 sysdev: remove gl... |
237 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
238 |
} |
1da177e4c Linux-2.6.12-rc2 |
239 |
/** |
25985edce Fix common misspe... |
240 |
* sysdev_driver_unregister - Remove an auxiliary driver. |
1da177e4c Linux-2.6.12-rc2 |
241 242 243 |
* @cls: Class driver belongs to. * @drv: Driver. */ |
60530afe1 Driver core: some... |
244 245 |
void sysdev_driver_unregister(struct sysdev_class *cls, struct sysdev_driver *drv) |
1da177e4c Linux-2.6.12-rc2 |
246 |
{ |
9f3f776bd sysdev: use mutex... |
247 |
mutex_lock(&sysdev_drivers_lock); |
f4203e303 sysdev: Do not re... |
248 |
__sysdev_driver_remove(cls, drv, NULL); |
9f3f776bd sysdev: use mutex... |
249 |
mutex_unlock(&sysdev_drivers_lock); |
1da177e4c Linux-2.6.12-rc2 |
250 |
} |
1da177e4c Linux-2.6.12-rc2 |
251 252 |
EXPORT_SYMBOL_GPL(sysdev_driver_register); EXPORT_SYMBOL_GPL(sysdev_driver_unregister); |
1da177e4c Linux-2.6.12-rc2 |
253 254 255 256 257 |
/** * sysdev_register - add a system device to the tree * @sysdev: device in question * */ |
60530afe1 Driver core: some... |
258 |
int sysdev_register(struct sys_device *sysdev) |
1da177e4c Linux-2.6.12-rc2 |
259 260 |
{ int error; |
60530afe1 Driver core: some... |
261 |
struct sysdev_class *cls = sysdev->cls; |
1da177e4c Linux-2.6.12-rc2 |
262 263 264 |
if (!cls) return -EINVAL; |
838ea8e8d sysdev: fix debug... |
265 266 267 |
pr_debug("Registering sys device of class '%s' ", kobject_name(&cls->kset.kobj)); |
61030bfb7 Kobject: change d... |
268 |
|
ef79df263 sysdev: fix probl... |
269 270 |
/* initialize the kobject to 0, in case it had previously been used */ memset(&sysdev->kobj, 0x00, sizeof(struct kobject)); |
1da177e4c Linux-2.6.12-rc2 |
271 272 |
/* Make sure the kset is set */ sysdev->kobj.kset = &cls->kset; |
1da177e4c Linux-2.6.12-rc2 |
273 |
/* Register the object */ |
61030bfb7 Kobject: change d... |
274 275 276 |
error = kobject_init_and_add(&sysdev->kobj, &ktype_sysdev, NULL, "%s%d", kobject_name(&cls->kset.kobj), sysdev->id); |
1da177e4c Linux-2.6.12-rc2 |
277 278 |
if (!error) { |
60530afe1 Driver core: some... |
279 |
struct sysdev_driver *drv; |
1da177e4c Linux-2.6.12-rc2 |
280 |
|
838ea8e8d sysdev: fix debug... |
281 282 283 |
pr_debug("Registering sys device '%s' ", kobject_name(&sysdev->kobj)); |
9f3f776bd sysdev: use mutex... |
284 |
mutex_lock(&sysdev_drivers_lock); |
1da177e4c Linux-2.6.12-rc2 |
285 286 287 |
/* Generic notification is implicit, because it's that * code that should have called us. */ |
25985edce Fix common misspe... |
288 |
/* Notify class auxiliary drivers */ |
1da177e4c Linux-2.6.12-rc2 |
289 290 291 292 |
list_for_each_entry(drv, &cls->drivers, entry) { if (drv->add) drv->add(sysdev); } |
9f3f776bd sysdev: use mutex... |
293 |
mutex_unlock(&sysdev_drivers_lock); |
79f0313bf driver core: sysd... |
294 |
kobject_uevent(&sysdev->kobj, KOBJ_ADD); |
1da177e4c Linux-2.6.12-rc2 |
295 |
} |
838ea8e8d sysdev: fix debug... |
296 |
|
1da177e4c Linux-2.6.12-rc2 |
297 298 |
return error; } |
60530afe1 Driver core: some... |
299 |
void sysdev_unregister(struct sys_device *sysdev) |
1da177e4c Linux-2.6.12-rc2 |
300 |
{ |
60530afe1 Driver core: some... |
301 |
struct sysdev_driver *drv; |
1da177e4c Linux-2.6.12-rc2 |
302 |
|
9f3f776bd sysdev: use mutex... |
303 |
mutex_lock(&sysdev_drivers_lock); |
1da177e4c Linux-2.6.12-rc2 |
304 305 306 307 |
list_for_each_entry(drv, &sysdev->cls->drivers, entry) { if (drv->remove) drv->remove(sysdev); } |
9f3f776bd sysdev: use mutex... |
308 |
mutex_unlock(&sysdev_drivers_lock); |
1da177e4c Linux-2.6.12-rc2 |
309 |
|
c10997f65 Kobject: convert ... |
310 |
kobject_put(&sysdev->kobj); |
1da177e4c Linux-2.6.12-rc2 |
311 |
} |
2e711c04d PM: Remove sysdev... |
312 313 |
EXPORT_SYMBOL_GPL(sysdev_register); EXPORT_SYMBOL_GPL(sysdev_unregister); |
1da177e4c Linux-2.6.12-rc2 |
314 |
|
9800794ac sysdev: Add utili... |
315 316 317 318 319 320 321 322 323 324 325 326 |
#define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr) ssize_t sysdev_store_ulong(struct sys_device *sysdev, struct sysdev_attribute *attr, const char *buf, size_t size) { struct sysdev_ext_attribute *ea = to_ext_attr(attr); char *end; unsigned long new = simple_strtoul(buf, &end, 0); if (end == buf) return -EINVAL; *(unsigned long *)(ea->var) = new; |
4e318d7c6 sysfs: Fix return... |
327 328 |
/* Always return full write size even if we didn't consume all */ return size; |
9800794ac sysdev: Add utili... |
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
} EXPORT_SYMBOL_GPL(sysdev_store_ulong); ssize_t sysdev_show_ulong(struct sys_device *sysdev, struct sysdev_attribute *attr, char *buf) { struct sysdev_ext_attribute *ea = to_ext_attr(attr); return snprintf(buf, PAGE_SIZE, "%lx ", *(unsigned long *)(ea->var)); } EXPORT_SYMBOL_GPL(sysdev_show_ulong); ssize_t sysdev_store_int(struct sys_device *sysdev, struct sysdev_attribute *attr, const char *buf, size_t size) { struct sysdev_ext_attribute *ea = to_ext_attr(attr); char *end; long new = simple_strtol(buf, &end, 0); if (end == buf || new > INT_MAX || new < INT_MIN) return -EINVAL; *(int *)(ea->var) = new; |
4e318d7c6 sysfs: Fix return... |
352 353 |
/* Always return full write size even if we didn't consume all */ return size; |
9800794ac sysdev: Add utili... |
354 355 356 357 358 359 360 361 362 363 364 365 |
} EXPORT_SYMBOL_GPL(sysdev_store_int); ssize_t sysdev_show_int(struct sys_device *sysdev, struct sysdev_attribute *attr, char *buf) { struct sysdev_ext_attribute *ea = to_ext_attr(attr); return snprintf(buf, PAGE_SIZE, "%d ", *(int *)(ea->var)); } EXPORT_SYMBOL_GPL(sysdev_show_int); |