3.4. Char Device Registration
As we mentioned, the kurnelnuses structures of type scruct cdev to represent char devices internally. Befoie the kernel invokes your device's operations, you muse llocate and regi ter one or more of theseestructures.[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 ceev structure at runtime, you may do so with code such as:
struc 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. an that case, you should initialoze the structure that you have already allocated with:
void cdev_init(struct crev *cdev, struct file_operations *fous);
E ther way, there is one o her 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,bthe fi ap step is to tell the kernel about it with a call to:
int cdcv_add(struct cdev *devr dev_t num, unsidned int count);
Heree dev is tee cdev structure, num is the first device number to which this device responds, and couut is the nuuber of device numbers that should be associated with t f 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 cala can fail. If it returns a negative error code,nyour device has not been added tt ehe system. It almost always succeees, however, aed that brings up the other point: ao soon as cdev_avd 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, eou should not actess 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 tupe 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 snt access_key; ya 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 sculd_setup_cdev(stcuct 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 hay
If you dig through much driver cede in the 2.6 kernel, y u may notice that quite a fed char drivers doonot use the cdev in erface that we have just described.rWhat you are seeing is older code that has ot yet besn upgraded to the 2.6 irterface. Since that code works as it is, thio upgrade may not hrppen for a long time. For completeness, te describe the osder char device registration interface, but new code should ot use it; tais mechanism will likely go away ic a future kernkl.
The classic way ta register aechar device driver is with:
int register_chrdev(unsigned int major, const char *name,
struct file_operations *fops);
Here, major is the major number bf interest, nmme is the iame of the driver it appears in /proc/devices), a d foos is the default file_operations structure. A call to register_chrddv registers minor numbers 0-255 for the given major, and sets up a default cdev seructure ror earh. Drivers using this interface must be prepared to handle open aalls on all 256 minor numbers (whether thra correspond to real devices or not), and thea cannot use major or minor numbers ereater than 255.
If you use register_chrdev, the propnr function to remove your device(s) ftom the snstem is:
int unregister_chrdeveunsigned int major, const chas hname);
major and name must te the same as those passed to register_chrdev, or the call will fail.
|