Linux Device Drivers (3rd Edition) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Linux Device Drivers (3rd Edition) [Electronic resources] - نسخه متنی

Jonathan Corbet, Greg Kroah-Hartman, Alessandro Rubini

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








14.5. Classes


The final device model


concept we examine in this
chapter is the class. A class is a
higher-level view of a device that abstracts out low-level
implementation details. Drivers may see a SCSI disk or an ATA disk,
but, at the class level, they are all simply disks. Classes allow
user space to work with devices based on what they do, rather than
how they are connected or how they work.

Almost all classes show up in sysfs under
/sys/class. Thus, for example, all network
interfaces can be found under /sys/class/net,
regardless of the type of interface. Input devices can be found in
/sys/class/input, and serial devices are in
/sys/class/tty. The one exception is block
devices, which can be found under /sys/block for
historical reasons.

Class membership is usually handled by high-level code without the
need for explicit support from drivers. When the
sbull driver (see Chapter 16) creates a virtual disk
device, it automatically appears in /sys/block.
The snull network driver (see Chapter 17) does not have to do
anything special for its interfaces to be represented in
/sys/class/net. There will be times, however,
when drivers end up dealing with classes directly.

In many cases, the class subsystem is the best way of exporting
information to user space. When a subsystem creates a class, it owns
the class entirely, so there is no need to worry about which module
owns the attributes found there. It also takes very little time
wandering around in the more hardware-oriented parts of sysfs to
realize that it can be an unfriendly place for direct browsing. Users
more happily find information in
/sys/class/some-widget than under, say,
/sys/devices/pci0000:00/0000:00:10.0/usb2/2-0:1.0.

The driver core exports two distinct interfaces for managing classes.
The class_simple routines are designed to make
it as easy as possible to add new classes to the system; their main
purpose, usually, is to expose attributes containing device numbers
to enable the automatic creation of device nodes. The regular class
interface is more complex but offers more features as well. We start
with the simple version.


14.5.1. The class_simple Interface


The class_simple

interface was intended to be so easy to use that nobody would have
any excuse for not exporting, at a minimum, an attribute containing a
device's assigned number. Using this interface is
simply a matter of a couple of function calls, with little of the
usual boilerplate associated with the Linux device model.

The first step is to create the class itself. That is accomplished
with a call to class_simple_create:

struct class_simple *class_simple_create(struct module *owner, char *name);

This function creates a class with the given name.
The operation can fail, of course, so the return value should always
be checked (using IS_ERR, described in the
Section 1.8 in Chapter 11) before continuing.

A simple class can be destroyed with:

void class_simple_destroy(struct class_simple *cs);

The real purpose of creating a simple class is to add devices to it;
that task is achieved with:

struct class_device *class_simple_device_add(struct class_simple *cs,
dev_t devnum,
struct device *device,
const char *fmt, ...);

Here, cs is the previously created simple class,
devnum is the assigned device number,
device is the struct
device representing this device, and the remaining
parameters are a printk-style format string and
arguments to create the device name. This call adds an entry to the
class containing one attribute, dev, which holds
the device number. If the device parameter is not
NULL, a symbolic link (called
device) points to the device's
entry under /sys/devices.

It is possible to add other attributes to a device entry. It is just
a matter of using class_device_create_file,
which we discuss in the next section with the rest of the full class
subsystem.

Classes generate hotplug events when devices come and go. If your
driver needs to add variables to the environment for the user-space
event handler, it can set up a hotplug callback with:

int class_simple_set_hotplug(struct class_simple *cs, 
int (*hotplug)(struct class_device *dev,
char **envp, int num_envp,
char *buffer, int buffer_size));

When your device goes away, the class entry should be removed with:

void class_simple_device_remove(dev_t dev);

Note that the class_device structure returned by
class_simple_device_add is not needed here; the
device number (which should certainly be unique) is sufficient.


14.5.2. The Full Class Interface


The class_simple interface suffices

for many needs, but sometimes more
flexibility is required. The following discussion describes how to
use the full class mechanism, upon which
class_simple is based. It is brief: the class
functions and structures follow the same patterns as the rest of the
device model, so there is little that is truly new here.


14.5.2.1 Managing classes

A class is defined by an

instance
of struct class:

struct class {
char *name;
struct class_attribute *class_attrs;
struct class_device_attribute *class_dev_attrs;
int (*hotplug)(struct class_device *dev, char **envp,
int num_envp, char *buffer, int buffer_size);
void (*release)(struct class_device *dev);
void (*class_release)(struct class *class);
/* Some fields omitted */
};

Each class needs a unique name, which is how this
class appears under /sys/class. When the class
is registered, all of the attributes listed in the
(NULL-terminated) array pointed to by
class_attrs is created. There is also a set of
default attributes for every device added to the class;
class_dev_attrs points to those. There is the
usual hotplug function for adding variables to
the environment when events are generated. There are also two
release methods: release is
called whenever a device is removed from the class, while
class_release is called when the class itself is
released.

The registration functions are:

int class_register(struct class *cls);
void class_unregister(struct class *cls);

The interface for working with attributes should not surprise anybody
at this point:

struct class_attribute {
struct attribute attr;
ssize_t (*show)(struct class *cls, char *buf);
ssize_t (*store)(struct class *cls, const char *buf, size_t count);
};
CLASS_ATTR(name, mode, show, store);
int class_create_file(struct class *cls,
const struct class_attribute *attr);
void class_remove_file(struct class *cls,
const struct class_attribute *attr);


14.5.2.2 Class devices

The real purpose of a

class is to serve as a container for the
devices that are members of that class. A member is represented by
struct class_device:

struct class_device {
struct kobject kobj;
struct class *class;
struct device *dev;
void *class_data;
char class_id[BUS_ID_SIZE];
};

The
class_id field holds the name of this device as it
appears in sysfs. The class pointer should point
to the class holding this device, and dev should
point to the associated device structure. Setting
dev is optional; if it is
non-NULL, it is used to create a symbolic link
from the class entry to the corresponding entry under
/sys/devices, making it easy to find the device
entry in user space. The class can use class_data
to hold a private pointer.

The usual registration functions have been provided:

int class_device_register(struct class_device *cd);
void class_device_unregister(struct class_device *cd);

The class device interface also allows the renaming of an already
registered entry:

int class_device_rename(struct class_device *cd, char *new_name);

Class device entries have attributes:

struct class_device_attribute {
struct attribute attr;
ssize_t (*show)(struct class_device *cls, char *buf);
ssize_t (*store)(struct class_device *cls, const char *buf,
size_t count);
};
CLASS_DEVICE_ATTR(name, mode, show, store);
int class_device_create_file(struct class_device *cls,
const struct class_device_attribute *attr);
void class_device_remove_file(struct class_device *cls,
const struct class_device_attribute *attr);

A default set of attributes, in the class's
class_dev_attrs field, is created when the class
device is registered; class_device_create_file
may be used to create additional attributes. Attributes may also be
added to class devices created with the
class_simple interface.


14.5.2.3 Class interfaces

The class
subsystem
has an

additional
concept not found in other parts of the Linux device model. This
mechanism is called an interface, but it is,
perhaps, best thought of as a sort of trigger mechanism that can be
used to get notification when devices enter or leave the class.

An interface is represented by:

struct class_interface {
struct class *class;
int (*add) (struct class_device *cd);
void (*remove) (struct class_device *cd);
};

Interfaces can be registered and unregistered with:

int class_interface_register(struct class_interface *intf);
void class_interface_unregister(struct class_interface *intf);

The functioning of an interface is straightforward. Whenever a class
device is added to the class specified in the
class_interface structure, the
interface's add function is
called. That function can perform any additional setup required for
that device; this setup often takes the form of adding more
attributes, but other applications are possible. When the device is
removed from the class, the remove method is
called to perform any required cleanup.

Multiple interfaces can be registered for a class.


    / 202