A device driver allows operating systems and programs to interact with hardware devices. This document discusses device drivers in Linux, including that drivers are loaded as kernel modules, communicate between user and kernel space, and have character, block, and network classes. It provides examples of initializing and removing a sample "memory" driver that allows reading from and writing to a character device memory buffer.
2. Introduction
• Defination :- Device driver or software driver is a
computer program allowing higher-level computer
programs to interact with a hardware device.
• A driver typically communicates with the device
through the computer bus or communications
subsystem to which the hardware connects.
• Drivers are hardware-dependent and operating-
system-specific. They usually provide the interrupt
handling required for any necessary asynchronous
time-dependent hardware interface.
3. Why a Device Driver?
• A device driver is usually part of the OS kernel
o Compiled with the OS
o Dynamically loaded into the OS during execution.
• Each device driver handles
o one device type (e.g., mouse)
o one class of closely related devices (e.g., SCSI disk driver to handle
multiple disks of different sizes and different speeds.).
• A device driver simplifies programming by acting as
translator between a hardware device and the
applications or operating systems that use it.
• Programmers can write the higher-level application
code independently of whatever specific hardware
device.
6. Processes in Linux
• When a user process executes a system call, it does
not transfer control to another process,
• but changes its execution mode from user to kernel
mode.
• In kernel mode, while executing the system call, the
process has access to the kernel address space, and
• Through supporting functions it has access to the
address space of the user executing the call.
7. Functions in Device Drivers
• Accept abstract read and write requests from the
device-independent layer above.
• Initialize the device.
• Manage power requirements and log events.
• Check input parameters if they are valid.
• Translate valid input from abstract to concrete terms
o e.g., convert linear block number into the head, track, sector and cylinder
number for disk access.
• Check the device if it is in use (i.e., check the status bit).
• Control the device by issuing a sequence of commands.
The driver determines what commands will be issued.
8. Loadable Kernel Module
• In computing, a loadable kernel module (or LKM) is an object
file that contains code to extend the running kernel, or so-
called base kernel, of an operating system.
• Most current Unix-like systems, and Microsoft Windows, support
loadable kernel modules.
• Without loadable kernel modules, an operating system would
have to have all possible anticipated functionality already
compiled directly into the base kernel.
• Much of that functionality would reside in memory without
being used, wasting memory, and would require that users
rebuild and reboot the base kernel every time new
functionality is desired.
• Most operating systems supporting loadable kernel modules
will include modules to support most desired functionality.
9. Classes of Devices and Modules
• The Linux way of looking at devices distinguishes
between three fundamental device types.
• Each module usually implements one of these types,
and thus is classifiable as
1.char module
2.block module
3.network module.
10. 1. Character devices
• A character (char) device is one that can be
accessed as a stream of bytes (like a file); a char
driver is in charge of implementing this behavior.
• Such a driver usually implements at least the open,
close, read, and write system calls.
• The text console (/dev/console) and the serial ports
(/dev/ttyS0 and friends) are examples of char devices,
as they are well represented by the stream
abstraction.
• Char devices are accessed by means of filesystem
nodes, such as /dev/tty1 and /dev/lp0.
• The only relevant difference between a char device
and a regular file is that you can always move back
and forth in the regular file, whereas most char
devices are just data channels, which you can only
access sequentially.
11. 2.Block devices
• Like char devices, block devices are accessed by
filesystem nodes in the /dev directory.
• A block device is a device (e.g., a disk) that can host a
filesystem.
• In most Unix systems, a block device can only handle I/O
operations that transfer one or more whole blocks, which
are usually 512 bytes (or a larger power of two) bytes in
length.
• Linux, instead, allows the application to read and write a
block device like a char device—it permits the transfer of
any number of bytes at a time.
• As a result, block and char devices differ only in the way
data is managed internally by the kernel, and thus in the
kernel/driver software interface.
• Like a char device, each block device is accessed
through a filesystem node, and the difference between
them is transparent to the user.
12. 3. Network interfaces
• Any network transaction is made through an interface,
that is, a device that is able to exchange data with other
hosts.
• Usually, an interface is a hardware device, but it might
also be a pure software device, like the loopback
interface.
• A network interface is in charge of sending and receiving
data packets, driven by the network subsystem of the
kernel, without knowing how individual transactions map
to the actual packets being transmitted.
• Many network connections (especially those using TCP)
are stream-oriented, but network devices are, usually,
designed around the transmission and receipt of packets.
• A network driver knows nothing about individual
connections; it only handles packets.
13. Major Minor Numbers
• Major device numbers are used by the Linux system
to map I/O requests to the driver code, thereby
deciding which device driver to execute, when a
user reads from or writes to the special file.
• The minor numbers are entirely under the control of
the driver writer, and usually refer to sub-devices of
the device.
• These sub-devices may be separate units attached
to a controller. Thus, a disk device driver may, for
example, communicate with a hardware controller
(the device) which has several disk drives (sub-
devices) attached.
14. Device Driver Protocol
o After driver knows which commands to issue, it
starts to write them into controller's device
registers .
o After writing each command, it checks to see if
the controller accepted the command and is
prepared to accept the next one.
o After commands have been issued, either (a) the
device waits until the controller does some work
and it blocks itself until interrupt comes to
unblock it; or (b) the device doesn't wait
because the command finished without any
delay.
15. Applications
• Because of the diversity of modern hardware and operating
systems, drivers operate in many different environments. Drivers
may interface with:
• Printers
• video adapters
• network cards
• sound cards
• local buses of various sorts — in particular, for bus mastering on
modern systems
• low-bandwidth I/O buses of various sorts (for pointing devices
such as mice, keyboards, USB, etc.)
• computer storage devices such as hard disk, CD-ROM and
floppy disk buses (ATA, SATA, SCSI)
• implementing support for different file systems
• image scanners
• digital cameras
16. Character Device Driver
• User Space and Kernel Space
• Loading and Removing the driver
in user space
• Loading and Removing the driver
in kernel space
• The complete driver “memory”
17. User space and kernel space
• When you write device drivers, it’s important to
make the distinction between “user space” and
“kernel space”.
• Kernel Space : Linux (which is a kernel) manages
the machine's hardware in a simple and efficient
manner, offering the user a simple and uniform
programming interface.
• In the same way, the kernel, and in particular its
device drivers, form a bridge or interface between
the end-user/programmer and the hardware.
• Any subroutines or functions forming part of the
kernel (modules and device drivers, for example)
are considered to be part of kernel space.
18. • User space : End-user programs, like the UNIX shell
or other GUI based applications (kpresenter for
example), are part of the user space.
• Obviously, these applications need to interact with
the system's hardware . However, they don’t do so
directly, but through the kernel supported
functions.
Device driver events and their associated interfacing functions between kernel space and user space.
Events User functions Kernel functions
Load module insmod module_init()
Open device fopen file_operations: open
Close device fread file_operations: read
Write device fwrite file_operations: write
Close device fclose file_operations: release
Remove module rmmod module_exit()
Device driver events and their associated functions between kernel space and the hardware device.
Events Kernel functions
Read data inb
Write data outb
19. Loading and Removing the driver in user space
• To implement simple character device driver in user
space make one file named “demo.c” and content of file
is :
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
• Next, you need to generate a makefile. The makefile for
this example, which should be named Makefile, will be:
obj-m := demo.o
• Unlike with previous versions of the kernel, it’s now also
necessary to compile the module using the same kernel
that you’re going to load and use the module with. To
compile it, you can type:
make -C /usr/src/kernel-source-2.6.8 M=`pwd` modules
20. In user space, you can load the module as root by typing the following
into the command line:
# insmod demo.ko
The insmod command allows the installation of the module in the kernel.
However, this particular module isn’t of much use.
It is possible to check that the module has been installed correctly by
looking at all installed modules:
# lsmod
Finally, the module can be removed from the kernel using the command:
# rmmod demo
By issuing the lsmod command again, you can verify that the module is
no longer in the kernel.
21. Loading and Removing the driver in kernel space
• When a module device driver is loaded into the
kernel, some preliminary tasks are usually performed
like resetting the device, reserving RAM, reserving
interrupts, and reserving input/output ports, etc.
• These tasks are performed, in kernel space, by two
functions which need to be present (and explicitly
declared): module_init and module_exit; they
correspond to the user space commands insmod
and rmmod , which are used when installing or
removing a module.
• To sum up, the user commands insmod and rmmod
use the kernel space functions module_init and
module_exit.
23. • The actual functions hello_init and hello_exit can be
given any name desired. However, in order for them to
be identified as the corresponding loading and removing
functions, they have to be passed as parameters to the
functions module_init and module_exit.
• The printk function has also been introduced. It is very
similar to the well known printf apart from the fact that it
only works inside the kernel. The <1> symbol shows the
high priority of the message (low number). In this way,
besides getting the message in the kernel system log files,
you should also receive this message in the system
console.
• This module can be compiled using the same command
as before, after adding its name into the Makefile and
content of it is : “obj-m := demo.o hello.o”.
24. The complete driver “memory”: initial part of the driver
• I’ll now show how to build a complete device driver: memory.c.
This device will allow a character to be read from or written into it.
This device, while normally not very useful, provides a very
illustrative example since it is a complete driver; it's also easy to
implement,since it doesn’t interface to a real hardware device.
• After the #include files, the functions that will be defined later are
declared.
• The common functions which are typically used to manipulate
files are declared in the definition of the file_operations structure.
These will also be explained in detail later. Next, the initialization
and exit functions—used when loading and removing the
module—are declared to the kernel.
• Finally, the global variables of the driver are declared: one of
them is the major number of the driver, the other is a pointer to a
region in memory, memory_buffer, which will be used as storage
for the driver data.
25. /* Necessary includes for device drivers */
#include <linux/init.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
MODULE_LICENSE("Dual BSD/GPL");
/* Declaration of memory.c functions */
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t
*f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t
*f_pos);
void memory_exit(void);
int memory_init(void);
/* Structure that declares the usual file */
/* access functions */
struct file_operations memory_fops = {
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
/* Declaration of the init and exit functions */
module_init(memory_init);
module_exit(memory_exit);
/* Global variables of the driver */
/* Major number */
int memory_major = 60;
/* Buffer to store data */
char *memory_buffer;
26. The “memory” driver: connection of the device with its files
• In UNIX and Linux, devices are accessed from user space in exactly the
same way as files are accessed. These device files are normally
subdirectories of the /dev directory.
• To link normal files with a kernel module two numbers are used: major
number and minor number. The major number is the one the kernel
uses to link a file with its driver. The minor number is for internal use of the
device and for simplicity it won’t be covered in this article.
• To achieve this, a file (which will be used to access the device driver)
must be created, by typing the following command as root:
• # mknod /dev/memory c 60 0
• In the above, c means that a char device is to be created, 60 is the
major number and 0 is the minor number.
• Within the driver, in order to link it with its corresponding /dev file in
kernel space, the register_chrdev function is used. It is called with three
arguments: major number, a string of characters showing the module
name, and a file_operations structure which links the call with the file
functions it defines. It is invoked, when installing the module, in this way:
• Also, note the use of the kmalloc function. This function is used for
memory allocation of the buffer in the device driver which resides in
kernel space. Its use is very similar to the well known malloc function.
Finally, if registering the major number or allocating the memory fails,
the module acts accordingly.
27. int memory_init(void) {
int result;
/* Registering device */
result = register_chrdev(memory_major, "memory", &memory_fops);
if (result < 0) {
printk(
"<1>memory: cannot obtain major number %dn", memory_major);
return result;
}
/* Allocating memory for the buffer */
memory_buffer = kmalloc(1, GFP_KERNEL);
if (!memory_buffer) {
result = -ENOMEM;
goto fail;
}
memset(memory_buffer, 0, 1);
printk("<1>Inserting memory modulen");
return 0;
fail:
memory_exit();
return result;
}
28. The “memory” driver: removing the driver
• In order to remove the module inside the memory_exit
function, the function unregsiter_chrdev needs to be present.
This will free the major number for the kernel.
• The buffer memory is also freed in this function, in order to
leave a clean kernel when removing the device driver.
void memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(memory_major, "memory");
/* Freeing buffer memory */
if (memory_buffer) {
kfree(memory_buffer);
}
printk("<1>Removing memory modulen");
}
29. The “memory” driver: opening the device as a file
• The kernel space function, which corresponds to opening a file in
user space (fopen), is the member open: of the file_operations
structure in the call to register_chrdev. In this case, it is the
memory_open function. It takes as arguments: an inode structure,
which sends information to the kernel regarding the major number
and minor number; and a file structure with information relative to
the different operations that can be performed on a file. Neither of
these functions will be covered in depth within this article.
• When a file is opened, it’s normally necessary to initialize driver
variables or reset the device. In this simple example, though, these
operations are not performed.
• The memory_open function can be seen below:
int memory_open(struct inode *inode, struct file *filp)
{
/* Success */ return 0;
}
30. The “memory” driver: closing the device as a file
• The corresponding function for closing a file in user space
(fclose) is the release: member of the file_operations structure
in the call to register_chrdev. In this particular case, it is the
function memory_release, which has as arguments an inode
structure and a file structure, just like before.
• When a file is closed, it’s usually necessary to free the used
memory and any variables related to the opening of the
device. But, once again, due to the simplicity of this example,
none of these operations are performed.
• The memory_release function is shown below:
int memory_release(struct inode *inode, struct file *filp)
{
/* Success */ return 0;
}
31. The “memory” driver: reading the device
• To read a device with the user function fread or
similar, the member read: of the file_operations
structure is used in the call to register_chrdev. This
time, it is the function memory_read. Its arguments
are: a type file structure; a buffer (buf), from which
the user space function (fread) will read; a counter
with the number of bytes to transfer (count), which
has the same value as the usual counter in the user
space function (fread); and finally, the position of
where to start reading the file (f_pos).
• In this simple case, the memory_read function
transfers a single byte from the driver buffer
(memory_buffer) to user space with the function
copy_to_user:
32. ssize_t memory_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
/* Transfering data to user space */
copy_to_user(buf,memory_buffer,1);
/* Changing reading position as best suits */
if (*f_pos == 0) {
*f_pos+=1;
return 1;
} else {
return 0;
}
}
• The reading position in the file (f_pos) is also changed. If
the position is at the beginning of the file, it is increased
by one and the number of bytes that have been
properly read is given as a return value, 1. If not at the
beginning of the file, an end of file (0) is returned since
the file only stores one byte.
33. The “memory” driver: writing to a device
• To write to a device with the user function fwrite or similar, the
member write: of the file_operations structure is used in the
call to register_chrdev.
• It is the function memory_write, in this particular example,
which has the following as arguments: a type file structure;
buf, a buffer in which the user space function (fwrite) will write;
count, a counter with the number of bytes to transfer, which
has the same values as the usual counter in the user space
function (fwrite); and finally, f_pos, the position of where to
start writing in the file.
ssize_t memory_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
char *tmp;
tmp=buf+count-1;
copy_from_user(memory_buffer,tmp,1);
return 1;
}
34. The complete “memory” driver
• By joining all of the previously shown code, the complete driver is achieved:
<memory.c> =
<memory initial>
<memory init module>
<memory exit module>
<memory open>
<memory release>
<memory read>
<memory write>
• Before this module can be used, you will need to compile it in the same way as with
previous modules. The module can then be loaded with:
• # insmod memory.ko
• It’s also convenient to unprotect the device:
• # chmod 666 /dev/memory
• If everything went well, you will have a device /dev/memory to which you can write
a string of characters and it will store the last one of them. You can perform the
operation like this:
• $ echo -n abcdef >/dev/memory
• To check the content of the device you can use a simple cat:
• $ cat /dev/memory
• The stored character will not change until it is overwritten or the module is removed.
35. USB Drivers
• The universal serial bus (USB) is a connection
between a host computer and a number of
peripheral devices.
• It was originally created to replace a wide range of
slow and different buses—the parallel, serial, and
keyboard connections—with a single bus type that
all devices could connect to.
• USB has grown beyond these slow connections and
now supports almost every type of device that can
be connected to a PC.
• The latest revision of the USB specification added
high-speed connections with a theoretical speed
limit of 480 MBps.
36. • Topologically, a USB subsystem is not laid out as a
bus; it is rather a tree built out of several point-to-point
links. The links are four-wire cables (ground, power,
and two signal wires) that connect a device and a
hub, just like twisted-pair Ethernet.
• The USB host controller is in charge of asking every
USB device if it has any data to send.
• Because of this topology, a USB device can never
start sending data without first being asked to by the
host controller.
• This configuration allows for a very easy plugand-play
type of system, whereby devices can be
automatically configured by the host computer.
37. • The USB protocol specifications define a set of
standards that any device of a specific type can
follow.
• If a device follows that standard, then a special
driver for that device is not necessary.
• These different types are called classes and consist
of things like storage devices, keyboards, mice,
joysticks, network devices, and modems.
• Other types of devices that do not fit into these
classes require a special vendor-specific driver to be
written for that specific device.
• Video devices and USB-to-serial devices are a good
example where there is no defined standard, and a
driver is needed for every different device from
different manufacturers.
38. USB Device Basics
• A USB device is a very complex thing, as described
in the official USB documentation (available at
http://www.usb.org).
• Fortunately, the Linux kernel provides a subsystem
called the USB core to handle most of the
complexity. This chapter describes the interaction
between a driver and the USB core.
• USB devices consist of configurations, interfaces,
and endpoints and how USB drivers bind to USB
interfaces, not the entire USB device.
39. 1. Endpoints
• The most basic form of USB communication is through
something called an endpoint.
• A USB endpoint can carry data in only one direction,
either from the host computer to the device (called an
OUT endpoint) or from the device to the host computer
(called an IN endpoint).
• Endpoints can be thought of as unidirectional pipes.
• A USB endpoint can be one of four different types that
describe how the data is transmitted:
• CONTROL:
• Control endpoints are used to allow access to different
parts of the USB device.
• They are commonly used for configuring the device,
retrieving information about the device, sending
commands to the device, or retrieving status reports
about the device. These endpoints are usually small in size.
40. • Every USB device has a control endpoint called “endpoint
0” that is used by the USB core to configure the device at
insertion time.
• These transfers are guaranteed by the USB protocol to
always have enough reserved bandwidth to make it
through to the device.
• INTERRUPT:
• Interrupt endpoints transfer small amounts of data at a
fixed rate every time the USB host asks the device for data.
• These endpoints are the primary transport method for USB
keyboards and mice.
• They are also commonly used to send data to USB devices
to control the device, but are not generally used to transfer
large amounts of data.
• These transfers are guaranteed by the USB protocol to
always have enough reserved bandwidth to make it
through.
41. • BULK:
• Bulk endpoints transfer large amounts of data. These endpoints
are usually much larger (they can hold more characters at once)
than interrupt endpoints.
• They are common for devices that need to transfer any data that
must get through with no data loss.
• These transfers are not guaranteed by the USB protocol to always
make it through in a specific amount of time.
• If there is not enough room on the bus to send the whole BULK
packet, it is split up across multiple transfers to or from the device.
These endpoints are common on printers, storage, and network
devices.
• ISOCHRONOUS:
• Isochronous endpoints also transfer large amounts of data, but
the data is not always guaranteed to make it through.
• These endpoints are used in devices that can handle loss of data,
and rely more on keepinga constant stream of data flowing.
• Real-time data collections, such as audio and video devices,
almost always use these endpoints.
42. 2. Interfaces
• USB endpoints are bundled up into interfaces. USB
interfaces handle only one type of a USB logical
connection, such as a mouse, a keyboard, or a
audio stream.
• Some USB devices have multiple interfaces, such as
a USB speaker that might consist of two interfaces: a
USB keyboard for the buttons and a USB audio
stream.
• Because a USB interface represents basic
functionality, each USB driver controls an interface;
so, for the speaker example, Linux needs two
different drivers for one hardware device.
43. 3. Configurations
• USB interfaces are themselves bundled up into
configurations.
• A USB device can have multiple configurations and
might switch between them in order to change the
state of the device.
• For example, some devices that allow firmware to be
downloaded to them contain multiple configurations
to accomplish this.
• A single configuration can be enabled only at one
point in time.
• Linux does not handle multiple configuration USB
devices very well, but, thankfully, they are rare.
44. • USB devices are quite complex and are made up of
lots of different logical units.
• The relationships among these units can be simply
described as follows:
A. Devices usually have one or more configurations.
B. Configurations often have one or more interfaces.
C. Interfaces usually have one or more settings.
D. Interfaces have zero or more endpoints.
45. References
• Websites
o www.en.wikipedia.org
o www.slideshare.in
• Books
o Linux Device Driver
• By Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman