Home arrow Kernal Programming arrow Char Drivers

Language Translator

Hacking Zone

Hacking Tools
Attacking

Configure Windows

Windows Configuration

Mix Tutorials

Asterisk
Website Building

Novels

Mix Novels

Human Personality

Body Language
Char Drivers Print E-mail
Article Index
Char Drivers
Page 2
Page 3
Page 4
Page 5
Page 6
Page 7

Char Drivers

 

              The goal of this chapter is to write a complete char device driver. We develop a character driver because this class is suitable for most simple hardware devices. Char drivers are also easier to understand than block drivers or network drivers (which we get to in later chapters). Our ultimate aim is to write a modularized char driver, but we won’t talk about modularization issues in this chapter.
                Throughout the chapter, we present code fragments extracted from a real device driver: scull (Simple Character Utility for Loading Localities). scull is a char driver that acts on a memory area as though it were a device. In this chapter, because of that peculiarity of scull, we use the word device interchangeably with “the memory area used by scull.”

 

               The advantage of scull is that it isn’t hardware dependent. scull just acts on some
               memory, allocated from the kernel. Anyone can compile and run scull, and scull is
               portable across the computer architectures on which Linux runs. On the other hand,
               the device doesn’t do anything “useful” other than demonstrate the interface
               between the kernel and char drivers and allow the user to run some tests.
               The Design of scull
               The first step of driver writing is defining the capabilities (the mechanism) the driver
               will offer to user programs. Since our “device” is part of the computer’s memory,
               we’re free to do what we want with it. It can be a sequential or random-access
               device, one device or many, and so on.
               To make scull useful as a template for writing real drivers for real devices, we’ll show
               you how to implement several device abstractions on top of the computer memory,
               each with a different personality.
               The scull source implements the following devices. Each kind of device implemented
               by the module is referred to as a type.
 

               scull0 to scull3

                     Four devices, each consisting of a memory area that is both global and persis-
                     tent. Global means that if the device is opened multiple times, the data con-
                     tained within the device is shared by all the file descriptors that opened it.
                     Persistent means that if the device is closed and reopened, data isn’t lost. This
                     device can be fun to work with, because it can be accessed and tested using con-
                     ventional commands, such as cp, cat, and shell I/O redirection.

               scullpipe0 to scullpipe3

                     Four FIFO (first-in-first-out) devices, which act like pipes. One process reads
                     what another process writes. If multiple processes read the same device, they
                     contend for data. The internals of scullpipe will show how blocking and non-
                     blocking read and write can be implemented without having to resort to inter-
                     rupts. Although real drivers synchronize with their devices using hardware
                     interrupts, the topic of blocking and nonblocking operations is an important one
                     and is separate from interrupt handling (covered in Chapter 10).
               scullsingle
               scullpriv
               sculluid
               scullwuid
                     These devices are similar to scull0 but with some limitations on when an open is
                     permitted. The first (scullsingle) allows only one process at a time to use the
                     driver, whereas scullpriv is private to each virtual console (or X terminal ses-
                     sion), because processes on each console/terminal get different memory areas.
                     sculluid and scullwuid can be opened multiple times, but only by one user at a
                     time; the former returns an error of “Device Busy” if another user is locking the
                     device, whereas the latter implements blocking open. These variations of scull
                     would appear to be confusing policy and mechanism, but they are worth look-
                     ing at, because some real-life devices require this sort of management.
               Each of the scull devices demonstrates different features of a driver and presents dif-
               ferent difficulties. This chapter covers the internals of scull0 to scull3; the more
               advanced devices are covered in Chapter 6. scullpipe is described in the section “A
               Blocking I/O Example,” and the others are described in “Access Control on a Device
               File.”

               Major and Minor Numbers

               Char devices are accessed through names in the filesystem. Those names are called
               special files or device files or simply nodes of the filesystem tree; they are convention-
               ally located in the /dev directory. Special files for char drivers are identified by a “c”
               in the first column of the output of ls –l. Block devices appear in /dev as well, but
               they are identified by a “b.” The focus of this chapter is on char devices, but much of
               the following information applies to block devices as well.
                                                                       
               If you issue the ls –l command, you’ll see two numbers (separated by a comma) in
               the device file entries before the date of the last modification, where the file length
               normally appears. These numbers are the major and minor device number for the
               particular device. The following listing shows a few devices as they appear on a typi-
               cal system. Their major numbers are 1, 4, 7, and 10, while the minors are 1, 3, 5, 64,
               65, and 129.
                      crw-rw-rw-          1 root       root          1,   3 Apr 11 2002 null
                      crw-------          1 root       root        10,    1 Apr 11 2002 psaux
                      crw-------          1 root       root          4,   1 Oct 28 03:04 tty1
                      crw-rw-rw-          1 root       tty           4, 64 Apr  11 2002 ttys0
                      crw-rw----          1 root       uucp          4, 65 Apr  11 2002 ttyS1
                      crw--w----          1 vcsa       tty           7,   1 Apr 11 2002 vcs1
                      crw--w----          1 vcsa       tty           7, 129 Apr 11 2002 vcsa1
                      crw-rw-rw-          1 root       root          1,   5 Apr 11 2002 zero
               Traditionally, the major number identifies the driver associated with the device. For
               example, /dev/null and /dev/zero are both managed by driver 1, whereas virtual con-
               soles and serial terminals are managed by driver 4; similarly, both vcs1 and vcsa1
               devices are managed by driver 7. Modern Linux kernels allow multiple drivers to
               share major numbers, but most devices that you will see are still organized on the
               one-major-one-driver principle.
               The minor number is used by the kernel to determine exactly which device is being
               referred to. Depending on how your driver is written (as we will see below), you can
               either get a direct pointer to your device from the kernel, or you can use the minor
               number yourself as an index into a local array of devices. Either way, the kernel itself
               knows almost nothing about minor numbers beyond the fact that they refer to
               devices implemented by your driver.
               The Internal Representation of Device Numbers
               Within the kernel, the dev_t type (defined in <linux/types.h>) is used to hold device
               numbers—both the major and minor parts. As of Version 2.6.0 of the kernel, dev_t is
               a 32-bit quantity with 12 bits set aside for the major number and 20 for the minor
               number. Your code should, of course, never make any assumptions about the inter-
               nal organization of device numbers; it should, instead, make use of a set of macros
               found in <linux/kdev_t.h>. To obtain the major or minor parts of a dev_t, use:
                     MAJOR(dev_t dev);
                     MINOR(dev_t dev);
               If, instead, you have the major and minor numbers and need to turn them into a dev_t,
               use:
                     MKDEV(int major, int minor);
               Note that the 2.6 kernel can accommodate a vast number of devices, while previous
               kernel versions were limited to 255 major and 255 minor numbers. One assumes
               that the wider range will be sufficient for quite some time, but the computing field is
               littered with erroneous assumptions of that nature. So you should expect that the
               format of dev_t could change again in the future; if you write your drivers carefully,
               however, these changes will not be a problem.



 
< Prev   Next >
Your Ad Here

Donate us!!

Enter Amount:

RSS socialnet

Add to MyYahoo!
Subscribe in NewsGator Online
Add to Newsburst
Add to Google
Add to My AOL
Add to Pluck
Subscribe in FeedLounge
Add to Windows Live
Add to NetVibes
Subscribe in Rojo
Subscribe in Bloglines
Add to MyMSN
Add to Plusmo for your cellphone
Add to PageFlakes
Add to Technorati
Add to BlinkBits