Linux Device Drivers 2nd Edition (779877), страница 33
Текст из файла (страница 33)
It is structured as a separate port of theLinux kernel, with its own arch/um subdirectory. It does not run on a new type ofhardware, however; instead, it runs on a virtual machine implemented on theLinux system call interface. Thus, User-Mode Linux allows the Linux kernel to runas a separate, user-mode process on a Linux system.Having a copy of the kernel running as a user-mode process brings a number ofadvantages. Because it is running on a constrained, virtual processor, a buggy kernel cannot damage the “real” system.
Different hardware and software configurations can be tried easily on the same box. And, perhaps most significantly forkernel developers, the user-mode kernel can be easily manipulated with gdb oranother debugger. After all, it is just another process. User-Mode Linux clearly hasthe potential to accelerate kernel development.As of this writing, User-Mode Linux is not distributed with the mainline kernel; itmust be downloaded from its web site (http://user-mode-linux.sourceforge.net).The word is that it will be integrated into an early 2.4 release after 2.4.0; it maywell be there by the time this book is published.12622 June 2001 16:35http://openlib.org.uaDebuggers and Related ToolsUser-Mode Linux also has some significant limitations as of this writing, most ofwhich will likely be addressed soon. The virtual processor currently works in auniprocessor mode only; the port runs on SMP systems without a problem, but itcan only emulate a uniprocessor host.
The biggest problem for driver writers,though, is that the user-mode kernel has no access to the host system’s hardware.Thus, while it can be useful for debugging most of the sample drivers in this book,User-Mode Linux is not yet useful for debugging drivers that have to deal with realhardware. Finally, User-Mode Linux only runs on the IA-32 architecture.Because work is under way to fix all of these problems, User-Mode Linux willlikely be an indispensable tool for Linux device driver programmers in the verynear future.The Linux Trace ToolkitThe Linux Trace Toolkit (LTT) is a kernel patch and a set of related utilities thatallow the tracing of events in the kernel. The trace includes timing informationand can create a reasonably complete picture of what happened over a givenperiod of time.
Thus, it can be used not only for debugging but also for trackingdown performance problems.LTT, along with extensive documentation, can be found on the Web at www.opersys.com/LTT.Dynamic ProbesDynamic Probes (or DProbes) is a debugging tool released (under the GPL) byIBM for Linux on the IA-32 architecture. It allows the placement of a “probe” atalmost any place in the system, in both user and kernel space. The probe consistsof some code (written in a specialized, stack-oriented language) that is executedwhen control hits the given point. This code can report information back to userspace, change registers, or do a number of other things.
The useful feature ofDProbes is that once the capability has been built into the kernel, probes can beinserted anywhere within a running system without kernel builds or reboots.DProbes can also work with the Linux Trace Toolkit to insert new tracing events atarbitrary locations.The DProbes tool can be downloaded from IBM’s open source site: oss.softwar e.ibm.com.12722 June 2001 16:35http://openlib.org.uaCHAPTER FIVEENHANCED CHARDRIVER OPERATIONSIn Chapter 3, we built a complete device driver that the user can write to and readfrom. But a real device usually offers more functionality than synchronous readand write.
Now that we’re equipped with debugging tools should something goawry, we can safely go ahead and implement new operations.What is normally needed, in addition to reading and writing the device, is the ability to perform various types of hardware control via the device driver. Controloperations are usually supported via the ioctl method. The alternative is to look atthe data flow being written to the device and use special sequences as controlcommands. This latter technique should be avoided because it requires reservingsome characters for controlling purposes; thus, the data flow can’t contain thosecharacters. Moreover, this technique turns out to be more complex to handle thanioctl.
Nonetheless, sometimes it’s a useful approach to device control and is usedby tty’s and other devices. We’ll describe it later in this chapter in ‘‘Device ControlWithout ioctl.’’As we suggested in the previous chapter, the ioctl system call offers a device specific entry point for the driver to handle ‘‘commands.’’ ioctl is device specific inthat, unlike read and other methods, it allows applications to access featuresunique to the hardware being driven, such as configuring the device and enteringor exiting operating modes.
These control operations are usually not availablethrough the read/write file abstraction. For example, everything you write to aserial port is used as communication data, and you cannot change the baud rateby writing to the device. That is what ioctl is for: controlling the I/O channel.Another important feature of real devices (unlike scull ) is that data being read orwritten is exchanged with other hardware, and some synchronization is needed.The concepts of blocking I/O and asynchronous notification fill the gap and areintroduced in this chapter by means of a modified scull device.
The driver usesinteraction between different processes to create asynchronous events. As with theoriginal scull, you don’t need special hardware to test the driver’s workings. Wewill definitely deal with real hardware, but not until Chapter 8.12822 June 2001 16:36http://openlib.org.uaioctlioctlThe ioctl function call in user space corresponds to the following prototype:int ioctl(int fd, int cmd, ...);The prototype stands out in the list of Unix system calls because of the dots,which usually represent not a variable number of arguments. In a real system,however, a system call can’t actually have a variable number of arguments. Systemcalls must have a well-defined number of arguments because user programs canaccess them only through hardware ‘‘gates,’’ as outlined in ‘‘User Space and KernelSpace’’ in Chapter 2.
Therefore, the dots in the prototype represent not a variablenumber of arguments but a single optional argument, traditionally identified aschar *argp. The dots are simply there to prevent type checking during compilation. The actual nature of the third argument depends on the specific control command being issued (the second argument). Some commands take no arguments,some take an integer value, and some take a pointer to other data.
Using a pointeris the way to pass arbitrary data to the ioctl call; the device will then be able toexchange any amount of data with user space.The ioctl driver method, on the other hand, receives its arguments according tothis declaration:int (*ioctl) (struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg);The inode and filp pointers are the values corresponding to the file descriptorfd passed on by the application and are the same parameters passed to the openmethod. The cmd argument is passed from the user unchanged, and the optionalarg argument is passed in the form of an unsigned long, regardless ofwhether it was given by the user as an integer or a pointer.
If the invoking program doesn’t pass a third argument, the arg value received by the driver operation has no meaningful value.Because type checking is disabled on the extra argument, the compiler can’t warnyou if an invalid argument is passed to ioctl, and the programmer won’t notice theerror until runtime. This lack of checking can be seen as a minor problem with theioctl definition, but it is a necessary price for the general functionality that ioctlprovides.As you might imagine, most ioctl implementations consist of a switch statementthat selects the correct behavior according to the cmd argument.
Different commands have different numeric values, which are usually given symbolic names tosimplify coding. The symbolic name is assigned by a preprocessor definition. Custom drivers usually declare such symbols in their header files; scull.h declaresthem for scull. User programs must, of course, include that header file as well tohave access to those symbols.12922 June 2001 16:36http://openlib.org.uaChapter 5: Enhanced Char Driver OperationsChoosing the ioctl CommandsBefore writing the code for ioctl, you need to choose the numbers that correspondto commands. Unfortunately, the simple choice of using small numbers startingfrom 1 and going up doesn’t work well.The command numbers should be unique across the system in order to preventerrors caused by issuing the right command to the wrong device.
Such a mismatchis not unlikely to happen, and a program might find itself trying to change thebaud rate of a non-serial-port input stream, such as a FIFO or an audio device. Ifeach ioctl number is unique, then the application will get an EINVAL error ratherthan succeeding in doing something unintended.To help programmers create unique ioctl command codes, these codes have beensplit up into several bitfields. The first versions of Linux used 16-bit numbers: thetop eight were the ‘‘magic’’ number associated with the device, and the bottomeight were a sequential number, unique within the device. This happened becauseLinus was ‘‘clueless’’ (his own word); a better division of bitfields was conceivedonly later.