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