at v2.6.13 397 lines 9.6 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 291 292/** 293 * sysdev_suspend - Suspend all system devices. 294 * @state: Power state to enter. 295 * 296 * We perform an almost identical operation as sys_device_shutdown() 297 * above, though calling ->suspend() instead. Interrupts are disabled 298 * when this called. Devices are responsible for both saving state and 299 * quiescing or powering down the device. 300 * 301 * This is only called by the device PM core, so we let them handle 302 * all synchronization. 303 */ 304 305int sysdev_suspend(pm_message_t state) 306{ 307 struct sysdev_class * cls; 308 309 pr_debug("Suspending System Devices\n"); 310 311 list_for_each_entry_reverse(cls, &system_subsys.kset.list, 312 kset.kobj.entry) { 313 struct sys_device * sysdev; 314 315 pr_debug("Suspending type '%s':\n", 316 kobject_name(&cls->kset.kobj)); 317 318 list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { 319 struct sysdev_driver * drv; 320 pr_debug(" %s\n", kobject_name(&sysdev->kobj)); 321 322 /* Call global drivers first. */ 323 list_for_each_entry(drv, &sysdev_drivers, entry) { 324 if (drv->suspend) 325 drv->suspend(sysdev, state); 326 } 327 328 /* Call auxillary drivers next. */ 329 list_for_each_entry(drv, &cls->drivers, entry) { 330 if (drv->suspend) 331 drv->suspend(sysdev, state); 332 } 333 334 /* Now call the generic one */ 335 if (cls->suspend) 336 cls->suspend(sysdev, state); 337 } 338 } 339 return 0; 340} 341 342 343/** 344 * sysdev_resume - Bring system devices back to life. 345 * 346 * Similar to sys_device_suspend(), but we iterate the list forwards 347 * to guarantee that parent devices are resumed before their children. 348 * 349 * Note: Interrupts are disabled when called. 350 */ 351 352int sysdev_resume(void) 353{ 354 struct sysdev_class * cls; 355 356 pr_debug("Resuming System Devices\n"); 357 358 list_for_each_entry(cls, &system_subsys.kset.list, kset.kobj.entry) { 359 struct sys_device * sysdev; 360 361 pr_debug("Resuming type '%s':\n", 362 kobject_name(&cls->kset.kobj)); 363 364 list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { 365 struct sysdev_driver * drv; 366 pr_debug(" %s\n", kobject_name(&sysdev->kobj)); 367 368 /* First, call the class-specific one */ 369 if (cls->resume) 370 cls->resume(sysdev); 371 372 /* Call auxillary drivers next. */ 373 list_for_each_entry(drv, &cls->drivers, entry) { 374 if (drv->resume) 375 drv->resume(sysdev); 376 } 377 378 /* Call global drivers. */ 379 list_for_each_entry(drv, &sysdev_drivers, entry) { 380 if (drv->resume) 381 drv->resume(sysdev); 382 } 383 384 } 385 } 386 return 0; 387} 388 389 390int __init system_bus_init(void) 391{ 392 system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj; 393 return subsystem_register(&system_subsys); 394} 395 396EXPORT_SYMBOL_GPL(sysdev_register); 397EXPORT_SYMBOL_GPL(sysdev_unregister);