Listing 3: a module illustrating how attributes can be exposed to sysfs via kobjects.

/* File sysfs_example.c
 * Copyright (c) 2004 Daniele Paolo Scarpazza <scarpaz@scarpaz.com>
 * This file is released under the GPL.
 */

#include <linux/module.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/sysfs.h> 
#include <linux/kobject.h> 

MODULE_DESCRIPTION("Example module illustrating the use of sysfs attributes.");
MODULE_AUTHOR("Daniele Paolo Scarpazza");
MODULE_LICENSE("GPL");

#define STRING_ATTR_LEN 32

static struct mydev_info_t {
  int        integer_attribute;                  // An integer attribute
  char       string_attribute[STRING_ATTR_LEN];  // A string attribute
  unsigned   hex_attribute;                      // A 32-bit attribute managed as hexadecimal
  struct     kobject kobj;                       // A kobject is embedded to expose above attributes
} dev_info;


/* The following function handles read events of any attribute in
 * kobjects of our type. In OO terms, this is a method of class "mydev_kobj_type".
 * - kobj is a pointer to the current kobject (like the "this" pointer in C++);
 * - attr is a pointer to the attr struct describing the attribute being read;
 * - buffer is the output buffer;
 * - the function should return the number of characters written to the buffer;
 * Always make sure to write <= PAGE_SIZE characters.
 */
static ssize_t show_example_attr(struct kobject * kobj, struct attribute * attr, char * buffer)
{
  /* To determine the structure where the current kobject is embedded in a type-safe 
   * and standard way, the macro "container_of" is used.
   */
  struct mydev_info_t * dev_info_p = container_of(kobj, struct mydev_info_t, kobj);

  printk(KERN_INFO "sysfs_example: show request for attribute %s\n", attr->name);

  if (strcmp(attr->name,"integer")==0)
    // The integer attribute was requested
    return snprintf(buffer, PAGE_SIZE, "%i\n", dev_info_p->integer_attribute);
  else if (strcmp(attr->name,"string")==0)
    // The string attribute was requested
    return snprintf(buffer, PAGE_SIZE, "%s\n", dev_info_p->string_attribute);
  else if (strcmp(attr->name,"hex")==0)
    // The hex attribute was requested
    return snprintf(buffer, PAGE_SIZE, "0x%x\n", dev_info_p->hex_attribute);
  else {
    // An unexpected attribute was requested
    printk(KERN_INFO "sysfs_example: unknown attribute requested\n");
    return 0;
  }
}


/* The following function handles write events of any attribute in
 * kobjects of our type. In OO terms, this is a method of class "mydev_kobj_type".
 * - kobj and attr are as above;
 * - buffer is the input buffer;
 * - size is the size of the input buffer;
 * - the function should return the number of characters used from the
 *   input buffer;
 */
static ssize_t store_example_attr(struct kobject * kobj, struct attribute * attr, const char * buffer, size_t size)
{
  /* To determine the structure where the current kobject is embedded in a type-safe and 
   * standard way, the macro "container_of" is used.
   */
  struct mydev_info_t * dev_info_p = container_of(kobj, struct mydev_info_t, kobj);
  
  printk(KERN_INFO "sysfs_example: store request for attribute %s\n", attr->name);

  if (strcmp(attr->name,"integer")==0) {
    // The integer attribute is being set
    sscanf(buffer, "%i", & dev_info_p->integer_attribute);
    return size;
  } else if (strcmp(attr->name,"string")==0) {
    // The string attribute is being set    
    sscanf(buffer, "%" __stringify(STRING_ATTR_LEN) "s\n", 
	   dev_info_p->string_attribute);
    return size;
  } else if (strcmp(attr->name,"hex")==0) {
    // The hex attribute is being set    
    sscanf(buffer, "0x%x\n", & dev_info_p->hex_attribute);
    return size;
  } else {
    // An unexpected attribute was set
    printk(KERN_INFO "sysfs_example: unknown attribute requested\n");
    return 0;
  }
}


/* The following function performs cleanup operations whenever a
 * kobject of type "mydev_kobj_type" is not needed anymore. In OO
 * terms, it corresponds to the destructor for class
 * "mydev_kobj_type".
 */
static void example_release(struct kobject * kobj) 
{
  // additional cleanup code here
}


/* Declare a struct of type sysfs_ops, indicating that the above
 * functions "show_example_attr" and "store_example_attr" should be used
 * as implementations for the show and store methods.
 */
static struct sysfs_ops example_sysfs_ops = {
  .show  = show_example_attr,
  .store = store_example_attr 
};


/* Declare a struct of type kobj_type. In OO terms, this equals the
 * definition of a class "mydev_kobj_type" which uses function
 * "example_release" as a class destructor and the functions indicated
 * above in "example_sysfs_ops" as class methods.
 */
static struct kobj_type mydev_kobj_type = {
  .release       = example_release,
  .sysfs_ops     = & example_sysfs_ops,
  .default_attrs = NULL 
};


/* For each attribute, a struct of type attribute should be declared.
 * The macro below automates this declaration. 
 */
#define DECLARE_EXAMPLE_ATTRIBUTE(_name_)               \
static struct attribute example_##_name_##_attr = {     \
  .name  = __stringify(_name_),                        \
  .owner = THIS_MODULE,                                \
  .mode  = S_IRUGO | S_IWUSR                           \
};



DECLARE_EXAMPLE_ATTRIBUTE(integer);
DECLARE_EXAMPLE_ATTRIBUTE(string);
DECLARE_EXAMPLE_ATTRIBUTE(hex);


// Perform module initialization
static int __init sysfs_module_init(void) 
{
  printk(KERN_INFO "sysfs_example: loading\n");    

  memset(&dev_info, 0, sizeof(dev_info));

  // Initializing the kobject embedded in our device info struct
  kobject_init(& dev_info.kobj);

  // Setting the kobject's type
  dev_info.kobj.ktype = & mydev_kobj_type;

  // Setting the kobject name (the same name appears in sysfs)
  kobject_set_name(& dev_info.kobj, "sysfs_example");

  // Adding the kobject to sysfs
  kobject_add(& dev_info.kobj);
  
  // Initialize attribute values
  dev_info.integer_attribute        =  123;
  strcpy(dev_info.string_attribute  ,  "test");
  dev_info.hex_attribute            =  0xDEADBEEF;

  // Expose attributes to sysfs entry
  sysfs_create_file(& dev_info.kobj, &example_integer_attr);
  sysfs_create_file(& dev_info.kobj, &example_string_attr);
  sysfs_create_file(& dev_info.kobj, &example_hex_attr);

  return 0;  
}


// Perform module cleanup
static void __exit sysfs_module_cleanup(void) 
{
  printk(KERN_INFO "sysfs_example: unloading\n");

  // Remove exposed attributes
  sysfs_remove_file(& dev_info.kobj, &example_integer_attr);
  sysfs_remove_file(& dev_info.kobj, &example_string_attr);
  sysfs_remove_file(& dev_info.kobj, &example_hex_attr);

  // Remove sysfs entry
  kobject_del(& dev_info.kobj);
}


module_init(sysfs_module_init);
module_exit(sysfs_module_cleanup);
