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

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

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

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

Jonathan Corbet, Greg Kroah-Hartman, Alessandro Rubini

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

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

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








3.5. open and release


Now that we've taken a quick look at the fields, we
start using them in real scull functions.


3.5.1. The open Method


The open
method is provided for a
driver
to do any initialization in preparation for later operations. In most
drivers, open should perform the following
tasks:

  • Check for device-specific errors (such as device-not-ready or similar
    hardware problems)

  • Initialize the device if it is being opened for the first time

  • Update the f_op pointer, if necessary

  • Allocate and fill any data structure to be put in
    filp->private_data


The first order of business, however, is usually to identify which
device is being opened. Remember that the prototype for the
open method is:

int (*open)(struct inode *inode, struct file *filp);

The inode argument has the information we need
in the form of its i_cdev field, which contains
the cdev structure we set up before. The only
problem is that we do not normally want the cdev
structure itself, we want the scull_dev structure
that contains that cdev structure. The C language
lets programmers play all sorts of tricks to make that kind of
conversion; programming such tricks is error prone, however, and
leads to code that is difficult for others to read and understand.
Fortunately, in this case, the kernel hackers have done the tricky
stuff for us, in the form of the container_of
macro, defined in <linux/kernel.h>:

container_of(pointer, container_type, container_field);

This macro takes a pointer to a field of type
container_field, within a structure of type
container_type, and returns a pointer to the
containing structure. In scull_open, this macro
is used to find the appropriate device structure:

struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */

Once it has found the scull_dev structure,
scull stores a pointer to it in the
private_data field of the file
structure for easier access in the future.

The other way to identify the device being opened is to look at the
minor number stored in the inode structure. If you
register your device with register_chrdev, you
must use this technique. Be sure to use iminor
to obtain the minor number from the inode
structure, and make sure that it corresponds to a device that your
driver is actually prepared to handle.

The (slightly simplified) code for scull_open is:

int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) {
scull_trim(dev); /* ignore errors */
}
return 0; /* success */
}

The code looks pretty sparse, because it doesn't do
any particular device handling when open is
called. It doesn't need to, because the
scull device is global and persistent by design.
Specifically, there's no action such as
"initializing the device on first
open," because we don't keep an
open count for sculls.

The only real operation performed on
the device is truncating it to a length of 0 when the device is
opened for writing. This is performed because, by design, overwriting
a scull device with a shorter file results in a
shorter device data area. This is similar to the way opening a
regular file for writing truncates it to zero length. The operation
does nothing if the device is opened for reading.

We'll see later how a real initialization works when we look
at the code for the other scull personalities.


3.5.2. The release Method




The role of the
release method is the



reverse of open. Sometimes
you'll find that the method implementation is called
device_close instead of
device_release. Either
way, the device method should perform the following tasks:

  • Deallocate anything that open allocated in
    filp->private_data

  • Shut down the device on last close


The basic form of scull has no hardware to shut
down, so the code required is minimal:[7]

[7] The other
flavors of the device are closed by different functions because
scull_open substituted a different
filp->f_op for each device.
We'll discuss these as we introduce each
flavor.


int scull_release(struct inode *inode, struct file *filp)
{
return 0;
}

You may be wondering what happens when a device file is closed more
times than it is opened. After all, the dup and
fork system calls create copies of open files
without calling open; each of those copies is
then closed at program termination. For example, most programs
don't open their stdin file (or
device), but all of them end up closing it. How does a driver know
when an open device file has really been closed?

The answer is simple: not every close system
call causes the release method to be invoked.
Only the calls that actually release the device data structure invoke
the methodhence its name. The kernel keeps a counter of how
many times a file structure is being used. Neither
fork nor dup creates a new
file structure (only open
does that); they just increment the counter in the existing
structure. The close system call executes the
release method only when the counter for the
file structure drops to 0,
which happens when the structure is destroyed. This relationship
between the release method and the
close system call guarantees that your driver
sees only one release call for each
open.


Note
that the flush method is
called every time an application calls close.
However, very few drivers implement flush,
because usually there's nothing to perform at close
time unless release is involved.

As you may imagine, the previous discussion applies even when the
application terminates without explicitly closing its open files: the
kernel automatically closes any file at process exit time by
internally using the close system call.


    / 202