linux/drivers/base/class.c
<<
>>
Prefs
   1/*
   2 * class.c - basic device class management
   3 *
   4 * Copyright (c) 2002-3 Patrick Mochel
   5 * Copyright (c) 2002-3 Open Source Development Labs
   6 * Copyright (c) 2003-2004 Greg Kroah-Hartman
   7 * Copyright (c) 2003-2004 IBM Corp.
   8 *
   9 * This file is released under the GPLv2
  10 *
  11 */
  12
  13#include <linux/config.h>
  14#include <linux/device.h>
  15#include <linux/module.h>
  16#include <linux/init.h>
  17#include <linux/string.h>
  18#include "base.h"
  19
  20#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
  21#define to_class(obj) container_of(obj, struct class, subsys.kset.kobj)
  22
  23static ssize_t
  24class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
  25{
  26        struct class_attribute * class_attr = to_class_attr(attr);
  27        struct class * dc = to_class(kobj);
  28        ssize_t ret = 0;
  29
  30        if (class_attr->show)
  31                ret = class_attr->show(dc, buf);
  32        return ret;
  33}
  34
  35static ssize_t
  36class_attr_store(struct kobject * kobj, struct attribute * attr,
  37                 const char * buf, size_t count)
  38{
  39        struct class_attribute * class_attr = to_class_attr(attr);
  40        struct class * dc = to_class(kobj);
  41        ssize_t ret = 0;
  42
  43        if (class_attr->store)
  44                ret = class_attr->store(dc, buf, count);
  45        return ret;
  46}
  47
  48static void class_release(struct kobject * kobj)
  49{
  50        struct class *class = to_class(kobj);
  51
  52        pr_debug("class '%s': release.\n", class->name);
  53
  54        if (class->class_release)
  55                class->class_release(class);
  56        else
  57                pr_debug("class '%s' does not have a release() function, "
  58                         "be careful\n", class->name);
  59}
  60
  61static struct sysfs_ops class_sysfs_ops = {
  62        .show   = class_attr_show,
  63        .store  = class_attr_store,
  64};
  65
  66static struct kobj_type ktype_class = {
  67        .sysfs_ops      = &class_sysfs_ops,
  68        .release        = class_release,
  69};
  70
  71/* Hotplug events for classes go to the class_obj subsys */
  72static decl_subsys(class, &ktype_class, NULL);
  73
  74
  75int class_create_file(struct class * cls, const struct class_attribute * attr)
  76{
  77        int error;
  78        if (cls) {
  79                error = sysfs_create_file(&cls->subsys.kset.kobj, &attr->attr);
  80        } else
  81                error = -EINVAL;
  82        return error;
  83}
  84
  85void class_remove_file(struct class * cls, const struct class_attribute * attr)
  86{
  87        if (cls)
  88                sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr);
  89}
  90
  91struct class * class_get(struct class * cls)
  92{
  93        if (cls)
  94                return container_of(subsys_get(&cls->subsys), struct class, subsys);
  95        return NULL;
  96}
  97
  98void class_put(struct class * cls)
  99{
 100        subsys_put(&cls->subsys);
 101}
 102
 103
 104static int add_class_attrs(struct class * cls)
 105{
 106        int i;
 107        int error = 0;
 108
 109        if (cls->class_attrs) {
 110                for (i = 0; attr_name(cls->class_attrs[i]); i++) {
 111                        error = class_create_file(cls,&cls->class_attrs[i]);
 112                        if (error)
 113                                goto Err;
 114                }
 115        }
 116 Done:
 117        return error;
 118 Err:
 119        while (--i >= 0)
 120                class_remove_file(cls,&cls->class_attrs[i]);
 121        goto Done;
 122}
 123
 124static void remove_class_attrs(struct class * cls)
 125{
 126        int i;
 127
 128        if (cls->class_attrs) {
 129                for (i = 0; attr_name(cls->class_attrs[i]); i++)
 130                        class_remove_file(cls,&cls->class_attrs[i]);
 131        }
 132}
 133
 134int class_register(struct class * cls)
 135{
 136        int error;
 137
 138        pr_debug("device class '%s': registering\n", cls->name);
 139
 140        INIT_LIST_HEAD(&cls->children);
 141        INIT_LIST_HEAD(&cls->interfaces);
 142        error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
 143        if (error)
 144                return error;
 145
 146        subsys_set_kset(cls, class_subsys);
 147
 148        error = subsystem_register(&cls->subsys);
 149        if (!error) {
 150                error = add_class_attrs(class_get(cls));
 151                class_put(cls);
 152        }
 153        return error;
 154}
 155
 156void class_unregister(struct class * cls)
 157{
 158        pr_debug("device class '%s': unregistering\n", cls->name);
 159        remove_class_attrs(cls);
 160        subsystem_unregister(&cls->subsys);
 161}
 162
 163
 164/* Class Device Stuff */
 165
 166int class_device_create_file(struct class_device * class_dev,
 167                             const struct class_device_attribute * attr)
 168{
 169        int error = -EINVAL;
 170        if (class_dev)
 171                error = sysfs_create_file(&class_dev->kobj, &attr->attr);
 172        return error;
 173}
 174
 175void class_device_remove_file(struct class_device * class_dev,
 176                              const struct class_device_attribute * attr)
 177{
 178        if (class_dev)
 179                sysfs_remove_file(&class_dev->kobj, &attr->attr);
 180}
 181
 182int class_device_create_bin_file(struct class_device *class_dev,
 183                                 struct bin_attribute *attr)
 184{
 185        int error = -EINVAL;
 186        if (class_dev)
 187                error = sysfs_create_bin_file(&class_dev->kobj, attr);
 188        return error;
 189}
 190
 191void class_device_remove_bin_file(struct class_device *class_dev,
 192                                  struct bin_attribute *attr)
 193{
 194        if (class_dev)
 195                sysfs_remove_bin_file(&class_dev->kobj, attr);
 196}
 197
 198static int class_device_dev_link(struct class_device * class_dev)
 199{
 200        if (class_dev->dev)
 201                return sysfs_create_link(&class_dev->kobj,
 202                                         &class_dev->dev->kobj, "device");
 203        return 0;
 204}
 205
 206static void class_device_dev_unlink(struct class_device * class_dev)
 207{
 208        sysfs_remove_link(&class_dev->kobj, "device");
 209}
 210
 211static int class_device_driver_link(struct class_device * class_dev)
 212{
 213        if ((class_dev->dev) && (class_dev->dev->driver))
 214                return sysfs_create_link(&class_dev->kobj,
 215                                         &class_dev->dev->driver->kobj, "driver");
 216        return 0;
 217}
 218
 219static void class_device_driver_unlink(struct class_device * class_dev)
 220{
 221        sysfs_remove_link(&class_dev->kobj, "driver");
 222}
 223
 224
 225static ssize_t
 226class_device_attr_show(struct kobject * kobj, struct attribute * attr,
 227                       char * buf)
 228{
 229        struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
 230        struct class_device * cd = to_class_dev(kobj);
 231        ssize_t ret = 0;
 232
 233        if (class_dev_attr->show)
 234                ret = class_dev_attr->show(cd, buf);
 235        return ret;
 236}
 237
 238static ssize_t
 239class_device_attr_store(struct kobject * kobj, struct attribute * attr,
 240                        const char * buf, size_t count)
 241{
 242        struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
 243        struct class_device * cd = to_class_dev(kobj);
 244        ssize_t ret = 0;
 245
 246        if (class_dev_attr->store)
 247                ret = class_dev_attr->store(cd, buf, count);
 248        return ret;
 249}
 250
 251static struct sysfs_ops class_dev_sysfs_ops = {
 252        .show   = class_device_attr_show,
 253        .store  = class_device_attr_store,
 254};
 255
 256static void class_dev_release(struct kobject * kobj)
 257{
 258        struct class_device *cd = to_class_dev(kobj);
 259        struct class * cls = cd->class;
 260
 261        pr_debug("device class '%s': release.\n", cd->class_id);
 262
 263        if (cls->release)
 264                cls->release(cd);
 265        else {
 266                printk(KERN_ERR "Device class '%s' does not have a release() function, "
 267                        "it is broken and must be fixed.\n",
 268                        cd->class_id);
 269                WARN_ON(1);
 270        }
 271}
 272
 273static struct kobj_type ktype_class_device = {
 274        .sysfs_ops      = &class_dev_sysfs_ops,
 275        .release        = class_dev_release,
 276};
 277
 278static int class_hotplug_filter(struct kset *kset, struct kobject *kobj)
 279{
 280        struct kobj_type *ktype = get_ktype(kobj);
 281
 282        if (ktype == &ktype_class_device) {
 283                struct class_device *class_dev = to_class_dev(kobj);
 284                if (class_dev->class)
 285                        return 1;
 286        }
 287        return 0;
 288}
 289
 290static char *class_hotplug_name(struct kset *kset, struct kobject *kobj)
 291{
 292        struct class_device *class_dev = to_class_dev(kobj);
 293
 294        return class_dev->class->name;
 295}
 296
 297static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
 298                         int num_envp, char *buffer, int buffer_size)
 299{
 300        struct class_device *class_dev = to_class_dev(kobj);
 301        int retval = 0;
 302        int i = 0;
 303        int length = 0;
 304
 305        pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
 306
 307        if (class_dev->dev) {
 308                /* add physical device, backing this device  */
 309                struct device *dev = class_dev->dev;
 310                char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
 311
 312                add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
 313                                    &length, "PHYSDEVPATH=%s", path);
 314                kfree(path);
 315
 316                /* add bus name of physical device */
 317                if (dev->bus)
 318                        add_hotplug_env_var(envp, num_envp, &i,
 319                                            buffer, buffer_size, &length,
 320                                            "PHYSDEVBUS=%s", dev->bus->name);
 321
 322                /* add driver name of physical device */
 323                if (dev->driver)
 324                        add_hotplug_env_var(envp, num_envp, &i,
 325                                            buffer, buffer_size, &length,
 326                                            "PHYSDEVDRIVER=%s", dev->driver->name);
 327
 328                /* terminate, set to next free slot, shrink available space */
 329                envp[i] = NULL;
 330                envp = &envp[i];
 331                num_envp -= i;
 332                buffer = &buffer[length];
 333                buffer_size -= length;
 334        }
 335
 336        if (class_dev->class->hotplug) {
 337                /* have the bus specific function add its stuff */
 338                retval = class_dev->class->hotplug (class_dev, envp, num_envp,
 339                                                    buffer, buffer_size);
 340                        if (retval) {
 341                        pr_debug ("%s - hotplug() returned %d\n",
 342                                  __FUNCTION__, retval);
 343                }
 344        }
 345
 346        return retval;
 347}
 348
 349static struct kset_hotplug_ops class_hotplug_ops = {
 350        .filter =       class_hotplug_filter,
 351        .name =         class_hotplug_name,
 352        .hotplug =      class_hotplug,
 353};
 354
 355static decl_subsys(class_obj, &ktype_class_device, &class_hotplug_ops);
 356
 357
 358static int class_device_add_attrs(struct class_device * cd)
 359{
 360        int i;
 361        int error = 0;
 362        struct class * cls = cd->class;
 363
 364        if (cls->class_dev_attrs) {
 365                for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {
 366                        error = class_device_create_file(cd,
 367                                                         &cls->class_dev_attrs[i]);
 368                        if (error)
 369                                goto Err;
 370                }
 371        }
 372 Done:
 373        return error;
 374 Err:
 375        while (--i >= 0)
 376                class_device_remove_file(cd,&cls->class_dev_attrs[i]);
 377        goto Done;
 378}
 379
 380static void class_device_remove_attrs(struct class_device * cd)
 381{
 382        int i;
 383        struct class * cls = cd->class;
 384
 385        if (cls->class_dev_attrs) {
 386                for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)
 387                        class_device_remove_file(cd,&cls->class_dev_attrs[i]);
 388        }
 389}
 390
 391void class_device_initialize(struct class_device *class_dev)
 392{
 393        kobj_set_kset_s(class_dev, class_obj_subsys);
 394        kobject_init(&class_dev->kobj);
 395        INIT_LIST_HEAD(&class_dev->node);
 396}
 397
 398int class_device_add(struct class_device *class_dev)
 399{
 400        struct class * parent = NULL;
 401        struct class_interface * class_intf;
 402        int error;
 403
 404        class_dev = class_device_get(class_dev);
 405        if (!class_dev)
 406                return -EINVAL;
 407
 408        if (!strlen(class_dev->class_id)) {
 409                error = -EINVAL;
 410                goto register_done;
 411        }
 412
 413        parent = class_get(class_dev->class);
 414
 415        pr_debug("CLASS: registering class device: ID = '%s'\n",
 416                 class_dev->class_id);
 417
 418        /* first, register with generic layer. */
 419        kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
 420        if (parent)
 421                class_dev->kobj.parent = &parent->subsys.kset.kobj;
 422
 423        if ((error = kobject_add(&class_dev->kobj)))
 424                goto register_done;
 425
 426        /* now take care of our own registration */
 427        if (parent) {
 428                down_write(&parent->subsys.rwsem);
 429                list_add_tail(&class_dev->node, &parent->children);
 430                list_for_each_entry(class_intf, &parent->interfaces, node)
 431                        if (class_intf->add)
 432                                class_intf->add(class_dev);
 433                up_write(&parent->subsys.rwsem);
 434        }
 435        class_device_add_attrs(class_dev);
 436        class_device_dev_link(class_dev);
 437        class_device_driver_link(class_dev);
 438
 439 register_done:
 440        if (error && parent)
 441                class_put(parent);
 442        class_device_put(class_dev);
 443        return error;
 444}
 445
 446int class_device_register(struct class_device *class_dev)
 447{
 448        class_device_initialize(class_dev);
 449        return class_device_add(class_dev);
 450}
 451
 452void class_device_del(struct class_device *class_dev)
 453{
 454        struct class * parent = class_dev->class;
 455        struct class_interface * class_intf;
 456
 457        if (parent) {
 458                down_write(&parent->subsys.rwsem);
 459                list_del_init(&class_dev->node);
 460                list_for_each_entry(class_intf, &parent->interfaces, node)
 461                        if (class_intf->remove)
 462                                class_intf->remove(class_dev);
 463                up_write(&parent->subsys.rwsem);
 464        }
 465
 466        class_device_dev_unlink(class_dev);
 467        class_device_driver_unlink(class_dev);
 468        class_device_remove_attrs(class_dev);
 469
 470        kobject_del(&class_dev->kobj);
 471
 472        if (parent)
 473                class_put(parent);
 474}
 475
 476void class_device_unregister(struct class_device *class_dev)
 477{
 478        pr_debug("CLASS: Unregistering class device. ID = '%s'\n",
 479                 class_dev->class_id);
 480        class_device_del(class_dev);
 481        class_device_put(class_dev);
 482}
 483
 484int class_device_rename(struct class_device *class_dev, char *new_name)
 485{
 486        int error = 0;
 487
 488        class_dev = class_device_get(class_dev);
 489        if (!class_dev)
 490                return -EINVAL;
 491
 492        pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id,
 493                 new_name);
 494
 495        strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN);
 496
 497        error = kobject_rename(&class_dev->kobj, new_name);
 498
 499        class_device_put(class_dev);
 500
 501        return error;
 502}
 503
 504struct class_device * class_device_get(struct class_device *class_dev)
 505{
 506        if (class_dev)
 507                return to_class_dev(kobject_get(&class_dev->kobj));
 508        return NULL;
 509}
 510
 511void class_device_put(struct class_device *class_dev)
 512{
 513        kobject_put(&class_dev->kobj);
 514}
 515
 516
 517int class_interface_register(struct class_interface *class_intf)
 518{
 519        struct class * parent;
 520        struct class_device * class_dev;
 521
 522        if (!class_intf || !class_intf->class)
 523                return -ENODEV;
 524
 525        parent = class_get(class_intf->class);
 526        if (!parent)
 527                return -EINVAL;
 528
 529        down_write(&parent->subsys.rwsem);
 530        list_add_tail(&class_intf->node, &parent->interfaces);
 531
 532        if (class_intf->add) {
 533                list_for_each_entry(class_dev, &parent->children, node)
 534                        class_intf->add(class_dev);
 535        }
 536        up_write(&parent->subsys.rwsem);
 537
 538        return 0;
 539}
 540
 541void class_interface_unregister(struct class_interface *class_intf)
 542{
 543        struct class * parent = class_intf->class;
 544        struct class_device *class_dev;
 545
 546        if (!parent)
 547                return;
 548
 549        down_write(&parent->subsys.rwsem);
 550        list_del_init(&class_intf->node);
 551
 552        if (class_intf->remove) {
 553                list_for_each_entry(class_dev, &parent->children, node)
 554                        class_intf->remove(class_dev);
 555        }
 556        up_write(&parent->subsys.rwsem);
 557
 558        class_put(parent);
 559}
 560
 561
 562
 563int __init classes_init(void)
 564{
 565        int retval;
 566
 567        retval = subsystem_register(&class_subsys);
 568        if (retval)
 569                return retval;
 570
 571        /* ick, this is ugly, the things we go through to keep from showing up
 572         * in sysfs... */
 573        subsystem_init(&class_obj_subsys);
 574        if (!class_obj_subsys.kset.subsys)
 575                        class_obj_subsys.kset.subsys = &class_obj_subsys;
 576        return 0;
 577}
 578
 579EXPORT_SYMBOL_GPL(class_create_file);
 580EXPORT_SYMBOL_GPL(class_remove_file);
 581EXPORT_SYMBOL_GPL(class_register);
 582EXPORT_SYMBOL_GPL(class_unregister);
 583EXPORT_SYMBOL_GPL(class_get);
 584EXPORT_SYMBOL_GPL(class_put);
 585
 586EXPORT_SYMBOL_GPL(class_device_register);
 587EXPORT_SYMBOL_GPL(class_device_unregister);
 588EXPORT_SYMBOL_GPL(class_device_initialize);
 589EXPORT_SYMBOL_GPL(class_device_add);
 590EXPORT_SYMBOL_GPL(class_device_del);
 591EXPORT_SYMBOL_GPL(class_device_get);
 592EXPORT_SYMBOL_GPL(class_device_put);
 593EXPORT_SYMBOL_GPL(class_device_create_file);
 594EXPORT_SYMBOL_GPL(class_device_remove_file);
 595EXPORT_SYMBOL_GPL(class_device_create_bin_file);
 596EXPORT_SYMBOL_GPL(class_device_remove_bin_file);
 597
 598EXPORT_SYMBOL_GPL(class_interface_register);
 599EXPORT_SYMBOL_GPL(class_interface_unregister);
 600
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.