Module 6 Device Driver

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 12

Module 6 – Device Drivers

MODULE 6

Device Driver : Device Characteristics ,Design and anatomy, Types of device driver, General Design –
Character Devices and character device drivers, Block Devices and Block device drivers.

1. Design of a Device Driver


A device driver is a computer program that operates or controls a particular type of device that is
attached to a computer. That is, a device driver is glue between an operating system and its I/O devices.
A driver typically communicates with the device through the computer bus or communications
subsystems to which the hardware connects. Device driver acts as translators, converting the generic
requests received from the operating system into commands that specific peripheral controllers can
understand. The relationship is illustrated in following figure.

The application software makes system calls to the operating system requesting services.
The operating system analyses these requests to the appropriate device driver. The device driver in
turn analyses the request from the operating system and, when necessary issues commands to the
hardware interface to perform the operations needed to service the request.

Without device drivers the operating system would be responsible for talking directly to the
hardware. This would require the operating system’s designer to include support for all of the
devices that users might want to connect to their computer. It would also mean that adding support
for a new device would mean modifying the operating system itself.

All the device driver writer has to do is to take detailed device-independent requests from
the operating system and to manipulate the hardware in order to fulfill the request. Drivers are
hardware-dependent and operating system specific.

Dept of CSE Page 1


Module 6 – Device Drivers

The kernel must have embedded in it a device driver for every peripheral present on a
system. To make the design of device drivers easier, we have divided the issues to be considered
into three broad categories: (Design issues of a device driver):

1. Operating system/Driver communications


2. Driver/Hardware Communications
3. Driver Operations.

The first category covers all of the issues related to the exchange of information between the
device driver and operating system. It also includes support functions that the kernel provides for
the benefits of the device driver.

The second covers those issues related to the exchange of the information between the
device driver and the device it controls. This also includes issues such as how software talks to
hardware – and how the hardware talks back.

The third covers issues related to the actual internal operation of the driver itself. This
includes:

Dept of CSE Page 2


Module 6 – Device Drivers

a. Interpreting commands received from the operating system


b. Scheduling multiple outstanding requests for service.
c. Managing the transfer of data across both interfaces (operating system and hardware)
d. Accepting and processing hardware interrupts
e. Maintaining the integrity of the driver’s and the kernel’s data structures.

2. The anatomy of a device driver


It might be helpful to consider the major components of a driver. A device driver has three
sides: one side talks to the rest of the kernel, one talks to the hardware and one talks to the user.

 K
ernel Interface
of a driver :

In order to talk to the kernel, the driver registers with subsystems to respond to
events. Such an event might be opening of a file, a page fault, the plugging in of a new USB
device, etc.

Dept of CSE Page 3


Module 6 – Device Drivers

 User interface of Device driver :


Users talk with device drivers through device files. Device files are a mechanism
supplied by the kernel precisely for this direct user-driver interface.
A driver is a set of routines that can be called by the operating system. A driver can
also contain:

i. Data structure private to the driver


ii. References to kernel data structures external to the driver.
iii. Routines private to the driver.

Most device drivers are written as a single source file. The initial part of the driver is
sometimes called the prologue. The prologue is everything before the first routine and like
most C programs, it contains :

 #include directives referencing header files which define various kernel data
types and structures.
 #define directives that provide mnemonic names for various constants used in the
driver
 Declaration of variables and data structures.

The remaining parts of the driver are the functions referenced by the operating system and
routines private to the driver.
Dept of CSE Page 4
Module 6 – Device Drivers

3. Characteristics of a device driver


There are many different device drivers in the Linux kernel, but they all share some common
attributes:

 kernel code
Device drivers are part of the kernel and, like other code within the kernel, if they go
wrong they can seriously damage the system. A badly written driver may even crash the
system, possibly corrupting file systems and losing data.
 Kernel interfaces
Device drivers must provide a standard interface to the Linux kernel or to the subsystem
that they are part of. For example, a SCSI device driver provides a SCSI device interface to the
SCSI subsystem which, in turn, provides both file I/O and buffer cache interfaces to the kernel.
 Kernel mechanisms and services
Device drivers make use of standard kernel services such as memory allocation,
interrupt delivery and wait queues to operate.
 Loadable
Most of the Linux device drivers can be loaded on demand as kernel modules when
they are needed and unloaded when they are no longer being used. This makes the kernel very
adaptable and efficient with the system's resources.
 Configurable
Linux device drivers can be built into the kernel. Which devices are built is
configurable when the kernel is compiled.
 Dynamic
As the system boots and each device driver is initialized it looks for the hardware
devices that it is controlling. It does not matter if the device being controlled by a particular
device driver does not exist. In this case the device driver is simply redundant and causes no
harm apart from occupying a little of the system's memory.

4. Types of Device Drivers


UNIX device drivers can be divided into four different types based entirely on differences in the
way they communicate with the UNIX operating system. The types are : Block, Character, Terminal
and STREAMS. The kernel data structures and routines vary between the various types of drivers.

These differences affect the type of devices that can be supported with each interface.

i. Block device drivers.

Dept of CSE Page 5


Module 6 – Device Drivers

Block drivers communicate with the operating system through a collection of fixed-sized buffers
as illustrated in the following figure.

The operating system manages a cache of these buffers and attempts to satisfy user requests
for data by accessing buffers in the cache. The driver is invoked only when the requested data is not
in the cache, or when buffers in the cache have been changed and must be written out.
Because of this buffer cache the driver is insulated from many of the details of the users’
requests and need only handle requests from the operating system to fill or empty fixed-size buffers.
Block drivers are used primarily to support devices that can contain file systems (such as
hard disks).

ii. Character Drivers

Character devices can handle I/O requests of arbitrary size and can be used to support almost
any type of device. Usually, character drivers are used for devices that either deal with data a byte at
a time or work best with data in chunks smaller or larger than the standard fixed-sized buffers used
by block drivers.

One of the major differences between block and character drivers, is that, while user processes
interact with block drivers only indirectly through the buffer cache, their relationship with character
drivers is very direct. This shown in the following figure.

Dept of CSE Page 6


Module 6 – Device Drivers

The I/O request is passed essentially unchanged to the driver to process and the character driver
is responsible for transferring the data directly to and from the user process’s memory.

iii. Terminal Drivers

Terminal drivers are really just character drivers specialized to deal with communication
terminals that connect users to the central UNIX computer system.

Terminal drivers are responsible not only for shipping data to and from users’ terminals, but also
for handling line editing, tab expansion and many other terminal functions that are part of the standard
UNIX terminal interface.

Because of this additional processing that terminal drivers must perform, it is useful to consider
terminal drivers as a separate types of driver altogether. The following figure shows the relationship
terminal driver with the kernel.

Dept of CSE Page 7


Module 6 – Device Drivers

iv. STREAMS Drivers

STREAMS drivers are used to handle high speed communication devices such as networking
adapters that deal with unusual sized chunks of data and that need to handle protocols.

Versions of UNIX prior to System V release 3 supported network devices using character
devices. Networking devices usually support a number of layered protocols. The character model
essentially required that each layer of the protocol be implemented within the single driver. This
lack of modularity and reusability reduced the efficiency of the system.

As a result Dennis Ritchie of Bell Laboratories developed an extension to the character


driver model called STREAMS. This made it possible to stack protocol processing modules
between the user process and the driver. It is illustrated in the following figure. Stacking modules in
this way makes it much easier to implement network protocols.

5. Device Drivers - General Design

5.1. Major and Minor Numbers

Char devices are accessed through names in the file system. Those names are called special
files or device files or simply nodes of the file system tree; they are conventionally 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".
Consider the following figure. It shows the output of the ls –l command.

Dept of CSE Page 8


Module 6 – Device Drivers

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 typical system. Their major numbers are 1, 4, 7, and 10,
while the minors are 1, 3, 5, 64, 65, and 129.
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 consoles 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.
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,

Dept of CSE Page 9


Module 6 – Device Drivers

of course, never make any assumptions about the internal 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);

5.2. Character Devices and Character Device Drivers

One of the first things your driver will need to do when setting up a char device is to obtain one or
more device numbers to work with. The necessary function for this task is register_chrdev_region,
which is declared in <linux/fs.h>:

int register_chrdev_region(dev_t first, unsigned int count,char *name);

Here, first is the beginning device number of the range you would like to allocate. The minor
number portion of first is often 0, but there is no requirement to that effect. count is the total
number of contiguous device numbers you are requesting. Note that, if count is large, the range you
request could spill over to the next major number; but everything will still work properly as long as
the number range you request is available. Finally, name is the name of the device that should be
associated with this number range; it will appear in /proc/devices and sysfs.
As with most kernel functions, the return value from register_chrdev_region will be 0, if the
allocation was successfully performed. In case of error, a negative error code will be returned, and
you will not have access to the requested region.
register_chrdev_region works well if you know ahead of time exactly which device numbers
you want. Often, however, you will not know which major numbers your device will use; there is a
constant effort within the Linux kernel development community to move over to the use of
dynamically-allocated device numbers. The kernel will happily allocate a major number for you on
the fly, but you must request this allocation by using a different function:

int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);

With this function, dev is an output-only parameter that will, on successful completion, hold the first
number in your allocated range. firstminor should be the requested first minor number to use; it is
usually 0. The count and name parameters work like those given to request_chrdev_region.
Regardless of how you allocate your device numbers, you should free them when they are no longer
in use. Device numbers are freed with:

void unregister_chrdev_region(dev_t first, unsigned int count);

The open Method

Dept of CSE Page 10


Module 6 – Device Drivers

The open method is provided for a driver to do any initialization in preparation for later
operations. In most drivers, open should perform the following tasks:
 Check for device-specific errors (such as device-not-ready or similar hardware problems)
 Initialize the device if it is being opened for the first time
 Update the f_op pointer, if necessary
 Allocate and fill any data structure to be put in filp->private_data
The first order of business, however, is usually to identify which device is being opened.
Remember that the prototype for the open method is:
int (*open)(struct inode *inode, struct file *filp);

The release Method


The role of the release method is the reverse of open. Sometimes you'll find that the method
implementation is called device_close instead of device_release. Either way, the device method
should perform the following tasks:
 Deallocate anything that open allocated in filp->private_data
 Shut down the device on last close
The basic form of scull has no hardware to shut down, so the code required is minimal:The
other flavors of the device are closed by different functions because scull_open substituted a
different filp->f_op for each device. We'll discuss these as we introduce each flavor.
int scull_release(struct inode *inode, struct file *filp)
{
return 0;
}

5.3. Block Devices and Block Device Drivers


The first step taken by most block drivers is to register themselves with the kernel. The function
for this task is register_blkdev (which is declared in <linux/fs.h>):

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

The arguments are the major number that your device will be using and the associated name
(which the kernel will display in /proc/devices). If major is passed as 0, the kernel allocates a new
major number and returns it to the caller. As always, a negative return value from register_blkdev
indicates that an error has occurred. The corresponding function for canceling a block driver
registration is:

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

Here, the arguments must match those passed to register_blkdev, or the function returns
-EINVAL and not unregister anything.

Read/ Write Operations


2 methods –
 Polling

Dept of CSE Page 11


Module 6 – Device Drivers

 Interrupt based
a. Direct I/O with polling – the device management software polls the device controller
status register to detect completion of the operation; device management is implemented
wholly in the device driver, if interrupts are not used
b. Interrupt driven direct I/O – interrupts simplify the software’s responsibility for
detecting operation completion; device management is implemented through the
interaction of a device driver and interrupt routine.

Polling
CPU is used( eg. by a device driver) , in a program code loop, to continuously check a
device to see if it is ready to accept data or commands , or produce output
Loop ( until device ready )
Check device
End loop
CPU is tied up in communication with device until I/O operation is done. No other useful
work can be accomplished by the CPU. Typically one CPU in the system , but many devices.

Interrupt based
 I/O via software polling can be inefficient
 Too much time spent by CPU waiting for devices.ie., amount of time between I/O operations is
large
 Only one CPU; polling ties up this resources
 Better to design differently
 Since CPU is rare resource, we need to keep it busy processing jobs
 Handle I/O as different type of event
 CPU has wire called an interrupt request line
 Instead of I/o controller setting status [busy] =0 control[ command –ready]=0, I/O controller sets
the interrupt request line to 1
 CPU, as part of instruction processing cycle, automatically checks interrupt request line.
 If it is set to 1, this generates an interrupt.

Dept of CSE Page 12

You might also like