at v2.6.25-rc2 457 lines 11 kB view raw
1/* 2 * sys.c - pseudo-bus for system 'devices' (cpus, PICs, timers, etc) 3 * 4 * Copyright (c) 2002-3 Patrick Mochel 5 * 2002-3 Open Source Development Lab 6 * 7 * This file is released under the GPLv2 8 * 9 * This exports a 'system' bus type. 10 * By default, a 'sys' bus gets added to the root of the system. There will 11 * always be core system devices. Devices can use sysdev_register() to 12 * add themselves as children of the system bus. 13 */ 14 15#include <linux/sysdev.h> 16#include <linux/err.h> 17#include <linux/module.h> 18#include <linux/kernel.h> 19#include <linux/init.h> 20#include <linux/slab.h> 21#include <linux/string.h> 22#include <linux/pm.h> 23#include <linux/device.h> 24#include <linux/mutex.h> 25 26#include "base.h" 27 28#define to_sysdev(k) container_of(k, struct sys_device, kobj) 29#define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr) 30 31 32static ssize_t 33sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer) 34{ 35 struct sys_device * sysdev = to_sysdev(kobj); 36 struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr); 37 38 if (sysdev_attr->show) 39 return sysdev_attr->show(sysdev, buffer); 40 return -EIO; 41} 42 43 44static ssize_t 45sysdev_store(struct kobject * kobj, struct attribute * attr, 46 const char * buffer, size_t count) 47{ 48 struct sys_device * sysdev = to_sysdev(kobj); 49 struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr); 50 51 if (sysdev_attr->store) 52 return sysdev_attr->store(sysdev, buffer, count); 53 return -EIO; 54} 55 56static struct sysfs_ops sysfs_ops = { 57 .show = sysdev_show, 58 .store = sysdev_store, 59}; 60 61static struct kobj_type ktype_sysdev = { 62 .sysfs_ops = &sysfs_ops, 63}; 64 65 66int sysdev_create_file(struct sys_device * s, struct sysdev_attribute * a) 67{ 68 return sysfs_create_file(&s->kobj, &a->attr); 69} 70 71 72void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a) 73{ 74 sysfs_remove_file(&s->kobj, &a->attr); 75} 76 77EXPORT_SYMBOL_GPL(sysdev_create_file); 78EXPORT_SYMBOL_GPL(sysdev_remove_file); 79 80#define to_sysdev_class(k) container_of(k, struct sysdev_class, kset.kobj) 81#define to_sysdev_class_attr(a) container_of(a, \ 82 struct sysdev_class_attribute, attr) 83 84static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr, 85 char *buffer) 86{ 87 struct sysdev_class * class = to_sysdev_class(kobj); 88 struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr); 89 90 if (class_attr->show) 91 return class_attr->show(class, buffer); 92 return -EIO; 93} 94 95static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr, 96 const char *buffer, size_t count) 97{ 98 struct sysdev_class * class = to_sysdev_class(kobj); 99 struct sysdev_class_attribute * class_attr = to_sysdev_class_attr(attr); 100 101 if (class_attr->store) 102 return class_attr->store(class, buffer, count); 103 return -EIO; 104} 105 106static struct sysfs_ops sysfs_class_ops = { 107 .show = sysdev_class_show, 108 .store = sysdev_class_store, 109}; 110 111static struct kobj_type ktype_sysdev_class = { 112 .sysfs_ops = &sysfs_class_ops, 113}; 114 115int sysdev_class_create_file(struct sysdev_class *c, 116 struct sysdev_class_attribute *a) 117{ 118 return sysfs_create_file(&c->kset.kobj, &a->attr); 119} 120EXPORT_SYMBOL_GPL(sysdev_class_create_file); 121 122void sysdev_class_remove_file(struct sysdev_class *c, 123 struct sysdev_class_attribute *a) 124{ 125 sysfs_remove_file(&c->kset.kobj, &a->attr); 126} 127EXPORT_SYMBOL_GPL(sysdev_class_remove_file); 128 129static struct kset *system_kset; 130 131int sysdev_class_register(struct sysdev_class * cls) 132{ 133 pr_debug("Registering sysdev class '%s'\n", 134 kobject_name(&cls->kset.kobj)); 135 INIT_LIST_HEAD(&cls->drivers); 136 cls->kset.kobj.parent = &system_kset->kobj; 137 cls->kset.kobj.ktype = &ktype_sysdev_class; 138 cls->kset.kobj.kset = system_kset; 139 kobject_set_name(&cls->kset.kobj, cls->name); 140 return kset_register(&cls->kset); 141} 142 143void sysdev_class_unregister(struct sysdev_class * cls) 144{ 145 pr_debug("Unregistering sysdev class '%s'\n", 146 kobject_name(&cls->kset.kobj)); 147 kset_unregister(&cls->kset); 148} 149 150EXPORT_SYMBOL_GPL(sysdev_class_register); 151EXPORT_SYMBOL_GPL(sysdev_class_unregister); 152 153static DEFINE_MUTEX(sysdev_drivers_lock); 154 155/** 156 * sysdev_driver_register - Register auxillary driver 157 * @cls: Device class driver belongs to. 158 * @drv: Driver. 159 * 160 * @drv is inserted into @cls->drivers to be 161 * called on each operation on devices of that class. The refcount 162 * of @cls is incremented. 163 */ 164 165int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) 166{ 167 int err = 0; 168 169 mutex_lock(&sysdev_drivers_lock); 170 if (cls && kset_get(&cls->kset)) { 171 list_add_tail(&drv->entry, &cls->drivers); 172 173 /* If devices of this class already exist, tell the driver */ 174 if (drv->add) { 175 struct sys_device *dev; 176 list_for_each_entry(dev, &cls->kset.list, kobj.entry) 177 drv->add(dev); 178 } 179 } else { 180 err = -EINVAL; 181 printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__); 182 WARN_ON(1); 183 } 184 mutex_unlock(&sysdev_drivers_lock); 185 return err; 186} 187 188 189/** 190 * sysdev_driver_unregister - Remove an auxillary driver. 191 * @cls: Class driver belongs to. 192 * @drv: Driver. 193 */ 194void sysdev_driver_unregister(struct sysdev_class * cls, 195 struct sysdev_driver * drv) 196{ 197 mutex_lock(&sysdev_drivers_lock); 198 list_del_init(&drv->entry); 199 if (cls) { 200 if (drv->remove) { 201 struct sys_device *dev; 202 list_for_each_entry(dev, &cls->kset.list, kobj.entry) 203 drv->remove(dev); 204 } 205 kset_put(&cls->kset); 206 } 207 mutex_unlock(&sysdev_drivers_lock); 208} 209 210EXPORT_SYMBOL_GPL(sysdev_driver_register); 211EXPORT_SYMBOL_GPL(sysdev_driver_unregister); 212 213 214 215/** 216 * sysdev_register - add a system device to the tree 217 * @sysdev: device in question 218 * 219 */ 220int sysdev_register(struct sys_device * sysdev) 221{ 222 int error; 223 struct sysdev_class * cls = sysdev->cls; 224 225 if (!cls) 226 return -EINVAL; 227 228 pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj)); 229 230 /* Make sure the kset is set */ 231 sysdev->kobj.kset = &cls->kset; 232 233 /* Register the object */ 234 error = kobject_init_and_add(&sysdev->kobj, &ktype_sysdev, NULL, 235 "%s%d", kobject_name(&cls->kset.kobj), 236 sysdev->id); 237 238 if (!error) { 239 struct sysdev_driver * drv; 240 241 mutex_lock(&sysdev_drivers_lock); 242 /* Generic notification is implicit, because it's that 243 * code that should have called us. 244 */ 245 246 /* Notify class auxillary drivers */ 247 list_for_each_entry(drv, &cls->drivers, entry) { 248 if (drv->add) 249 drv->add(sysdev); 250 } 251 mutex_unlock(&sysdev_drivers_lock); 252 } 253 kobject_uevent(&sysdev->kobj, KOBJ_ADD); 254 return error; 255} 256 257void sysdev_unregister(struct sys_device * sysdev) 258{ 259 struct sysdev_driver * drv; 260 261 mutex_lock(&sysdev_drivers_lock); 262 list_for_each_entry(drv, &sysdev->cls->drivers, entry) { 263 if (drv->remove) 264 drv->remove(sysdev); 265 } 266 mutex_unlock(&sysdev_drivers_lock); 267 268 kobject_put(&sysdev->kobj); 269} 270 271 272 273/** 274 * sysdev_shutdown - Shut down all system devices. 275 * 276 * Loop over each class of system devices, and the devices in each 277 * of those classes. For each device, we call the shutdown method for 278 * each driver registered for the device - the auxillaries, 279 * and the class driver. 280 * 281 * Note: The list is iterated in reverse order, so that we shut down 282 * child devices before we shut down thier parents. The list ordering 283 * is guaranteed by virtue of the fact that child devices are registered 284 * after their parents. 285 */ 286 287void sysdev_shutdown(void) 288{ 289 struct sysdev_class * cls; 290 291 pr_debug("Shutting Down System Devices\n"); 292 293 mutex_lock(&sysdev_drivers_lock); 294 list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { 295 struct sys_device * sysdev; 296 297 pr_debug("Shutting down type '%s':\n", 298 kobject_name(&cls->kset.kobj)); 299 300 list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { 301 struct sysdev_driver * drv; 302 pr_debug(" %s\n", kobject_name(&sysdev->kobj)); 303 304 /* Call auxillary drivers first */ 305 list_for_each_entry(drv, &cls->drivers, entry) { 306 if (drv->shutdown) 307 drv->shutdown(sysdev); 308 } 309 310 /* Now call the generic one */ 311 if (cls->shutdown) 312 cls->shutdown(sysdev); 313 } 314 } 315 mutex_unlock(&sysdev_drivers_lock); 316} 317 318static void __sysdev_resume(struct sys_device *dev) 319{ 320 struct sysdev_class *cls = dev->cls; 321 struct sysdev_driver *drv; 322 323 /* First, call the class-specific one */ 324 if (cls->resume) 325 cls->resume(dev); 326 327 /* Call auxillary drivers next. */ 328 list_for_each_entry(drv, &cls->drivers, entry) { 329 if (drv->resume) 330 drv->resume(dev); 331 } 332} 333 334/** 335 * sysdev_suspend - Suspend all system devices. 336 * @state: Power state to enter. 337 * 338 * We perform an almost identical operation as sys_device_shutdown() 339 * above, though calling ->suspend() instead. Interrupts are disabled 340 * when this called. Devices are responsible for both saving state and 341 * quiescing or powering down the device. 342 * 343 * This is only called by the device PM core, so we let them handle 344 * all synchronization. 345 */ 346 347int sysdev_suspend(pm_message_t state) 348{ 349 struct sysdev_class * cls; 350 struct sys_device *sysdev, *err_dev; 351 struct sysdev_driver *drv, *err_drv; 352 int ret; 353 354 pr_debug("Suspending System Devices\n"); 355 356 list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { 357 pr_debug("Suspending type '%s':\n", 358 kobject_name(&cls->kset.kobj)); 359 360 list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { 361 pr_debug(" %s\n", kobject_name(&sysdev->kobj)); 362 363 /* Call auxillary drivers first */ 364 list_for_each_entry(drv, &cls->drivers, entry) { 365 if (drv->suspend) { 366 ret = drv->suspend(sysdev, state); 367 if (ret) 368 goto aux_driver; 369 } 370 } 371 372 /* Now call the generic one */ 373 if (cls->suspend) { 374 ret = cls->suspend(sysdev, state); 375 if (ret) 376 goto cls_driver; 377 } 378 } 379 } 380 return 0; 381 /* resume current sysdev */ 382cls_driver: 383 drv = NULL; 384 printk(KERN_ERR "Class suspend failed for %s\n", 385 kobject_name(&sysdev->kobj)); 386 387aux_driver: 388 if (drv) 389 printk(KERN_ERR "Class driver suspend failed for %s\n", 390 kobject_name(&sysdev->kobj)); 391 list_for_each_entry(err_drv, &cls->drivers, entry) { 392 if (err_drv == drv) 393 break; 394 if (err_drv->resume) 395 err_drv->resume(sysdev); 396 } 397 398 /* resume other sysdevs in current class */ 399 list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { 400 if (err_dev == sysdev) 401 break; 402 pr_debug(" %s\n", kobject_name(&err_dev->kobj)); 403 __sysdev_resume(err_dev); 404 } 405 406 /* resume other classes */ 407 list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) { 408 list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { 409 pr_debug(" %s\n", kobject_name(&err_dev->kobj)); 410 __sysdev_resume(err_dev); 411 } 412 } 413 return ret; 414} 415 416 417/** 418 * sysdev_resume - Bring system devices back to life. 419 * 420 * Similar to sys_device_suspend(), but we iterate the list forwards 421 * to guarantee that parent devices are resumed before their children. 422 * 423 * Note: Interrupts are disabled when called. 424 */ 425 426int sysdev_resume(void) 427{ 428 struct sysdev_class * cls; 429 430 pr_debug("Resuming System Devices\n"); 431 432 list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) { 433 struct sys_device * sysdev; 434 435 pr_debug("Resuming type '%s':\n", 436 kobject_name(&cls->kset.kobj)); 437 438 list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { 439 pr_debug(" %s\n", kobject_name(&sysdev->kobj)); 440 441 __sysdev_resume(sysdev); 442 } 443 } 444 return 0; 445} 446 447 448int __init system_bus_init(void) 449{ 450 system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); 451 if (!system_kset) 452 return -ENOMEM; 453 return 0; 454} 455 456EXPORT_SYMBOL_GPL(sysdev_register); 457EXPORT_SYMBOL_GPL(sysdev_unregister);