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