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

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

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

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

Jonathan Corbet, Greg Kroah-Hartman, Alessandro Rubini

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

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

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








3.4. Char Device Registration


As we mentioned, the kernel uses

structures of type
struct cdev to represent char
devices internally. Before the kernel invokes your
device's operations, you must allocate and register
one or more of these structures.[6] To do so, your code should include
<linux/cdev.h>, where the structure and
its associated helper functions are defined.

[6] There is an older
mechanism that avoids the use of cdev structures
(which we discuss in Section 3.4.2). New code should use the newer technique,
however.


There are two ways of allocating and initializing one of these
structures. If you wish to obtain a standalone
cdev structure at runtime, you may do so with code
such as:

struct cdev *my_cdev = cdev_alloc(  );
my_cdev->ops = &my_fops;

Chances are, however, that you will want to embed the
cdev structure within a device-specific structure
of your own; that is what scull does. In that
case, you should initialize the structure that you have already
allocated with:

void cdev_init(struct cdev *cdev, struct file_operations *fops);

Either way, there is one other struct
cdev field that you need to initialize. Like the
file_operations structure,
struct cdev has an
owner field that should be set to
THIS_MODULE.

Once the cdev

structure is set up, the final
step is to tell the kernel about it with a call to:

int cdev_add(struct cdev *dev, dev_t num, unsigned int count);

Here, dev is the cdev
structure, num is the first device number to which
this device responds, and count is the number of
device numbers that should be associated with the device. Often
count is one, but there are situations where it
makes sense to have more than one device number correspond to a
specific device. Consider, for example, the SCSI tape driver, which
allows user space to select operating modes (such as density) by
assigning multiple minor numbers to each physical device.

There are a couple of important things to keep in mind when using
cdev_add. The first is that this call can fail.
If it returns a negative error code, your device has not been added
to the system. It almost always succeeds, however, and that brings up
the other point: as soon as cdev_add returns,
your device is "live" and its
operations can be called by the kernel. You should not call
cdev_add until your driver is completely ready
to handle operations on the device.

To remove a char device from the system, call:

void cdev_del(struct cdev *dev);

Clearly, you should not access the cdev structure
after passing it to cdev_del.


3.4.1. Device Registration in scull


Internally, scull represents each device
with a structure of type
struct scull_dev. This
structure is defined as:

struct scull_dev {
struct scull_qset *data; /* Pointer to first quantum set */
int quantum; /* the current quantum size */
int qset; /* the current array size */
unsigned long size; /* amount of data stored here */
unsigned int access_key; /* used by sculluid and scullpriv */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};

We discuss the various fields in this structure as we come to them,
but for now, we call attention to cdev, the
struct cdev that interfaces our device to the
kernel. This structure must be initialized and added to the system as
described above; the scull code that handles
this task is:

static void scull_setup_cdev(struct scull_dev *dev, int index)
{
int err, devno = MKDEV(scull_major, scull_minor + index);
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_fops;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}

Since the cdev structure is embedded within
struct scull_dev,
cdev_init must be called to perform the
initialization of that structure.


3.4.2. The Older Way


If you dig through much driver code in the 2.6 kernel, you may notice
that quite a few char drivers do not use the cdev
interface that we have just described. What you are seeing is older
code that has not yet been upgraded to the 2.6 interface. Since that
code works as it is, this upgrade may not happen for a long time. For
completeness, we describe the

older char device
registration interface, but new code should not use it; this
mechanism will likely go away in a future kernel.

The classic way to register a char device driver is with:

int register_chrdev(unsigned int major, const char *name,
struct file_operations *fops);

Here, major is the major number
of interest,
name is the name of the driver (it appears in
/proc/devices), and fops is
the default file_operations structure. A call to
register_chrdev registers minor numbers 0-255
for the given major, and sets up a default
cdev structure for each. Drivers using this
interface must be prepared to handle open calls
on all 256 minor numbers (whether they correspond to real devices or
not), and they cannot use major or minor numbers greater than 255.

If you use register_chrdev, the proper function
to remove your device(s) from the system is:

int unregister_chrdev(unsigned int major, const char *name);

major and name must be
the



same as
those passed to register_chrdev, or the call
will fail.


    / 202