Linux Device Drivers 2nd Edition (779877), страница 16
Текст из файла (страница 16)
sculluid and scullwuid can beopened multiple times, but only by one user at a time; the former returns anerror of “Device Busy” if another user is locking the device, whereas the latterimplements blocking open. These variations of scull add more “policy” than“mechanism;” this kind of behavior is interesting to look at anyway, becausesome devices require types of management like the ones shown in these scullvariations as part of their mechanism.Each of the scull devices demonstrates different features of a driver and presentsdifferent difficulties. This chapter covers the internals of scull0 to skull3; the moreadvanced devices are covered in Chapter 5: scullpipe is described in “A SampleImplementation: scullpipe” and the others in “Access Control on a Device File.”Major and Minor NumbersChar devices are accessed through names in the filesystem.
Those names arecalled special files or device files or simply nodes of the filesystem tree; they areconventionally located in the /dev directory. Special files for char drivers are5522 June 2001 16:35http://openlib.org.uaChapter 3: Char Driversidentified by a “c” in the first column of the output of ls –l. Block devices appearin /dev as well, but they are identified by a “b.” The focus of this chapter is onchar devices, but much of the following information applies to block devices aswell.If you issue the ls –l command, you’ll see two numbers (separated by a comma) inthe device file entries before the date of last modification, where the file lengthnormally appears.
These numbers are the major device number and minor devicenumber for the particular device. The following listing shows a few devices asthey appear on a typical system. Their major numbers are 1, 4, 7, and 10, whilethe minors are 1, 3, 5, 64, 65, and 129.crw-rw-rwcrw------crw------crw-rw-rwcrw-rw-rwcrw------crw------crw-rw-rw-11111111rootrootrubinirootrootrootrootrootroot1,root10,tty4,dialout 4,dialout 4,sys7,sys7,root1,311646511295FebFebAugJunAugFebFebFeb23231630162323231999199922:2211:1900:00199919991999nullpsauxtty1ttyS0ttyS1vcs1vcsa1zeroThe major number identifies the driver associated with the device. For example,/dev/null and /dev/zer o are both managed by driver 1, whereas virtual consolesand serial terminals are managed by driver 4; similarly, both vcs1 and vcsa1devices are managed by driver 7.
The kernel uses the major number at open timeto dispatch execution to the appropriate driver.The minor number is used only by the driver specified by the major number; otherparts of the kernel don’t use it, and merely pass it along to the driver. It is common for a driver to control several devices (as shown in the listing); the minornumber provides a way for the driver to differentiate among them.Version 2.4 of the kernel, though, introduced a new (optional) feature, the devicefile system or devfs.
If this file system is used, management of device files is simplified and quite different; on the other hand, the new filesystem brings severaluser-visible incompatibilities, and as we are writing it has not yet been chosen as adefault feature by system distributors. The previous description and the followinginstructions about adding a new driver and special file assume that devfs is notpresent. The gap is filled later in this chapter, in “The Device Filesystem.”When devfs is not being used, adding a new driver to the system means assigninga major number to it.
The assignment should be made at driver (module) initialization by calling the following function, defined in <linux/fs.h>:int register_chrdev(unsigned int major, const char *name,struct file_operations *fops);5622 June 2001 16:35http://openlib.org.uaMajor and Minor NumbersThe return value indicates success or failure of the operation. A negative returncode signals an error; a 0 or positive return code reports successful completion.The major argument is the major number being requested, name is the name ofyour device, which will appear in /pr oc/devices, and fops is the pointer to anarray of function pointers, used to invoke your driver’s entry points, as explainedin “File Operations,” later in this chapter.The major number is a small integer that serves as the index into a static array ofchar drivers; “Dynamic Allocation of Major Numbers” later in this chapter explainshow to select a major number.
The 2.0 kernel supported 128 devices; 2.2 and 2.4increased that number to 256 (while reserving the values 0 and 255 for futureuses). Minor numbers, too, are eight-bit quantities; they aren’t passed to register_chrdev because, as stated, they are only used by the driver itself. There istremendous pressure from the developer community to increase the number ofpossible devices supported by the kernel; increasing device numbers to at least 16bits is a stated goal for the 2.5 development series.Once the driver has been registered in the kernel table, its operations are associated with the given major number. Whenever an operation is performed on a character device file associated with that major number, the kernel finds and invokesthe proper function from the file_operations structure.
For this reason, thepointer passed to register_chrdev should point to a global structure within thedriver, not to one local to the module’s initialization function.The next question is how to give programs a name by which they can requestyour driver. A name must be inserted into the /dev directory and associated withyour driver’s major and minor numbers.The command to create a device node on a filesystem is mknod; superuser privileges are required for this operation.
The command takes three arguments in addition to the name of the file being created. For example, the commandmknod /dev/scull0 c 254 0creates a char device (c) whose major number is 254 and whose minor number is0. Minor numbers should be in the range 0 to 255 because, for historical reasons,they are sometimes stored in a single byte. There are sound reasons to extend therange of available minor numbers, but for the time being, the eight-bit limit is stillin force.Please note that once created by mknod, the special device file remains unless it isexplicitly deleted, like any information stored on disk.
You may want to removethe device created in this example by issuing rm /dev/scull0.Dynamic Allocation of Major NumbersSome major device numbers are statically assigned to the most common devices. Alist of those devices can be found in Documentation/devices.txt within the kernel5722 June 2001 16:35http://openlib.org.uaChapter 3: Char Driverssource tree. Because many numbers are already assigned, choosing a unique number for a new driver can be difficult — there are far more custom drivers than available major numbers.
You could use one of the major numbers reserved for“experimental or local use,”* but if you experiment with several “local” drivers oryou publish your driver for third parties to use, you’ll again experience the problem of choosing a suitable number.Fortunately (or rather, thanks to someone’s ingenuity), you can request dynamicassignment of a major number.
If the argument major is set to 0 when you callregister_chrdev, the function selects a free number and returns it. The major number returned is always positive, while negative return values are error codes.Please note the behavior is slightly different in the two cases: the function returnsthe allocated major number if the caller requests a dynamic number, but returns 0(not the major number) when successfully registering a predefined major number.For private drivers, we strongly suggest that you use dynamic allocation to obtainyour major device number, rather than choosing a number randomly from theones that are currently free. If, on the other hand, your driver is meant to be useful to the community at large and be included into the official kernel tree, you’llneed to apply to be assigned a major number for exclusive use.The disadvantage of dynamic assignment is that you can’t create the device nodesin advance because the major number assigned to your module can’t be guaranteed to always be the same.
This means that you won’t be able to use loading-ondemand of your driver, an advanced feature introduced in Chapter 11. For normaluse of the driver, this is hardly a problem, because once the number has beenassigned, you can read it from /pr oc/devices.To load a driver using a dynamic major number, therefore, the invocation of insmod can be replaced by a simple script that after calling insmod reads/pr oc/devices in order to create the special file(s).A typical /pr oc/devices file looks like the following:Character devices:1 mem2 pty3 ttyp4 ttyS6 lp7 vcs10 misc13 input14 sound21 sg180 usb* Major numbers in the ranges 60 to 63, 120 to 127, and 240 to 254 are reserved for localand experimental use: no real device will be assigned such major numbers.5822 June 2001 16:35http://openlib.org.uaMajor and Minor NumbersBlock devices:2 fd8 sd11 sr65 sd66 sdThe script to load a module that has been assigned a dynamic number can thus bewritten using a tool such as awk to retrieve information from /pr oc/devices in orderto create the files in /dev.The following script, scull_load, is part of the scull distribution.