linux/drivers/base/sys.c
<<
>>
Prefs
   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
  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 0;
  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 0;
  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 */
  82decl_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(global_drivers);
 106
 107/**
 108 *      sysdev_driver_register - Register auxillary driver
 109 *      @cls:   Device class driver belongs to.
 110 *      @drv:   Driver.
 111 *
 112 *      If @cls is valid, then @drv is inserted into @cls->drivers to be
 113 *      called on each operation on devices of that class. The refcount
 114 *      of @cls is incremented.
 115 *      Otherwise, @drv is inserted into global_drivers, and called for
 116 *      each device.
 117 */
 118
 119int sysdev_driver_register(struct sysdev_class * cls,
 120                           struct sysdev_driver * drv)
 121{
 122        down_write(&system_subsys.rwsem);
 123        if (cls && kset_get(&cls->kset)) {
 124                list_add_tail(&drv->entry, &cls->drivers);
 125
 126                /* If devices of this class already exist, tell the driver */
 127                if (drv->add) {
 128                        struct sys_device *dev;
 129                        list_for_each_entry(dev, &cls->kset.list, kobj.entry)
 130                                drv->add(dev);
 131                }
 132        } else
 133                list_add_tail(&drv->entry, &global_drivers);
 134        up_write(&system_subsys.rwsem);
 135        return 0;
 136}
 137
 138
 139/**
 140 *      sysdev_driver_unregister - Remove an auxillary driver.
 141 *      @cls:   Class driver belongs to.
 142 *      @drv:   Driver.
 143 */
 144void sysdev_driver_unregister(struct sysdev_class * cls,
 145                              struct sysdev_driver * drv)
 146{
 147        down_write(&system_subsys.rwsem);
 148        list_del_init(&drv->entry);
 149        if (cls) {
 150                if (drv->remove) {
 151                        struct sys_device *dev;
 152                        list_for_each_entry(dev, &cls->kset.list, kobj.entry)
 153                                drv->remove(dev);
 154                }
 155                kset_put(&cls->kset);
 156        }
 157        up_write(&system_subsys.rwsem);
 158}
 159
 160EXPORT_SYMBOL_GPL(sysdev_driver_register);
 161EXPORT_SYMBOL_GPL(sysdev_driver_unregister);
 162
 163
 164
 165/**
 166 *      sysdev_register - add a system device to the tree
 167 *      @sysdev:        device in question
 168 *
 169 */
 170int sysdev_register(struct sys_device * sysdev)
 171{
 172        int error;
 173        struct sysdev_class * cls = sysdev->cls;
 174
 175        if (!cls)
 176                return -EINVAL;
 177
 178        /* Make sure the kset is set */
 179        sysdev->kobj.kset = &cls->kset;
 180
 181        /* But make sure we point to the right type for sysfs translation */
 182        sysdev->kobj.ktype = &ktype_sysdev;
 183        error = kobject_set_name(&sysdev->kobj, "%s%d",
 184                         kobject_name(&cls->kset.kobj), sysdev->id);
 185        if (error)
 186                return error;
 187
 188        pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj));
 189
 190        /* Register the object */
 191        error = kobject_register(&sysdev->kobj);
 192
 193        if (!error) {
 194                struct sysdev_driver * drv;
 195
 196                down_write(&system_subsys.rwsem);
 197                /* Generic notification is implicit, because it's that
 198                 * code that should have called us.
 199                 */
 200
 201                /* Notify global drivers */
 202                list_for_each_entry(drv, &global_drivers, entry) {
 203                        if (drv->add)
 204                                drv->add(sysdev);
 205                }
 206
 207                /* Notify class auxillary drivers */
 208                list_for_each_entry(drv, &cls->drivers, entry) {
 209                        if (drv->add)
 210                                drv->add(sysdev);
 211                }
 212                up_write(&system_subsys.rwsem);
 213        }
 214        return error;
 215}
 216
 217void sysdev_unregister(struct sys_device * sysdev)
 218{
 219        struct sysdev_driver * drv;
 220
 221        down_write(&system_subsys.rwsem);
 222        list_for_each_entry(drv, &global_drivers, entry) {
 223                if (drv->remove)
 224                        drv->remove(sysdev);
 225        }
 226
 227        list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
 228                if (drv->remove)
 229                        drv->remove(sysdev);
 230        }
 231        up_write(&system_subsys.rwsem);
 232
 233        kobject_unregister(&sysdev->kobj);
 234}
 235
 236
 237
 238/**
 239 *      sysdev_shutdown - Shut down all system devices.
 240 *
 241 *      Loop over each class of system devices, and the devices in each
 242 *      of those classes. For each device, we call the shutdown method for
 243 *      each driver registered for the device - the globals, the auxillaries,
 244 *      and the class driver.
 245 *
 246 *      Note: The list is iterated in reverse order, so that we shut down
 247 *      child devices before we shut down thier parents. The list ordering
 248 *      is guaranteed by virtue of the fact that child devices are registered
 249 *      after their parents.
 250 */
 251
 252void sysdev_shutdown(void)
 253{
 254        struct sysdev_class * cls;
 255
 256        pr_debug("Shutting Down System Devices\n");
 257
 258        down_write(&system_subsys.rwsem);
 259        list_for_each_entry_reverse(cls, &system_subsys.kset.list,
 260                                    kset.kobj.entry) {
 261                struct sys_device * sysdev;
 262
 263                pr_debug("Shutting down type '%s':\n",
 264                         kobject_name(&cls->kset.kobj));
 265
 266                list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
 267                        struct sysdev_driver * drv;
 268                        pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 269
 270                        /* Call global drivers first. */
 271                        list_for_each_entry(drv, &global_drivers, entry) {
 272                                if (drv->shutdown)
 273                                        drv->shutdown(sysdev);
 274                        }
 275
 276                        /* Call auxillary drivers next. */
 277                        list_for_each_entry(drv, &cls->drivers, entry) {
 278                                if (drv->shutdown)
 279                                        drv->shutdown(sysdev);
 280                        }
 281
 282                        /* Now call the generic one */
 283                        if (cls->shutdown)
 284                                cls->shutdown(sysdev);
 285                }
 286        }
 287        up_write(&system_subsys.rwsem);
 288}
 289
 290
 291/**
 292 *      sysdev_suspend - Suspend all system devices.
 293 *      @state:         Power state to enter.
 294 *
 295 *      We perform an almost identical operation as sys_device_shutdown()
 296 *      above, though calling ->suspend() instead. Interrupts are disabled
 297 *      when this called. Devices are responsible for both saving state and
 298 *      quiescing or powering down the device.
 299 *
 300 *      This is only called by the device PM core, so we let them handle
 301 *      all synchronization.
 302 */
 303
 304int sysdev_suspend(u32 state)
 305{
 306        struct sysdev_class * cls;
 307
 308        pr_debug("Suspending System Devices\n");
 309
 310        list_for_each_entry_reverse(cls, &system_subsys.kset.list,
 311                                    kset.kobj.entry) {
 312                struct sys_device * sysdev;
 313
 314                pr_debug("Suspending type '%s':\n",
 315                         kobject_name(&cls->kset.kobj));
 316
 317                list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
 318                        struct sysdev_driver * drv;
 319                        pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 320
 321                        /* Call global drivers first. */
 322                        list_for_each_entry(drv, &global_drivers, entry) {
 323                                if (drv->suspend)
 324                                        drv->suspend(sysdev, state);
 325                        }
 326
 327                        /* Call auxillary drivers next. */
 328                        list_for_each_entry(drv, &cls->drivers, entry) {
 329                                if (drv->suspend)
 330                                        drv->suspend(sysdev, state);
 331                        }
 332
 333                        /* Now call the generic one */
 334                        if (cls->suspend)
 335                                cls->suspend(sysdev, state);
 336                }
 337        }
 338        return 0;
 339}
 340
 341
 342/**
 343 *      sysdev_resume - Bring system devices back to life.
 344 *
 345 *      Similar to sys_device_suspend(), but we iterate the list forwards
 346 *      to guarantee that parent devices are resumed before their children.
 347 *
 348 *      Note: Interrupts are disabled when called.
 349 */
 350
 351int sysdev_resume(void)
 352{
 353        struct sysdev_class * cls;
 354
 355        pr_debug("Resuming System Devices\n");
 356
 357        list_for_each_entry(cls, &system_subsys.kset.list, kset.kobj.entry) {
 358                struct sys_device * sysdev;
 359
 360                pr_debug("Resuming type '%s':\n",
 361                         kobject_name(&cls->kset.kobj));
 362
 363                list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
 364                        struct sysdev_driver * drv;
 365                        pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 366
 367                        /* First, call the class-specific one */
 368                        if (cls->resume)
 369                                cls->resume(sysdev);
 370
 371                        /* Call auxillary drivers next. */
 372                        list_for_each_entry(drv, &cls->drivers, entry) {
 373                                if (drv->resume)
 374                                        drv->resume(sysdev);
 375                        }
 376
 377                        /* Call global drivers. */
 378                        list_for_each_entry(drv, &global_drivers, entry) {
 379                                if (drv->resume)
 380                                        drv->resume(sysdev);
 381                        }
 382
 383                }
 384        }
 385        return 0;
 386}
 387
 388
 389int __init system_bus_init(void)
 390{
 391        system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj;
 392        return subsystem_register(&system_subsys);
 393}
 394
 395EXPORT_SYMBOL_GPL(sysdev_register);
 396EXPORT_SYMBOL_GPL(sysdev_unregister);
 397
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.