An introduction to block device drivers

Last month, we inaugurated a column on Linux kernel programming with an article on how to write Linux device drivers without doing any kernel programming. This month we touch the kernel as we explore block device drivers.

We have already seen several macros which are very helpful in writing block device drivers. Many of these are defined in drivers/block/blk.h, and have to be specially set up.

At the top of the device driver, after including the standard include files your driver needs (which must include linux/major.h and linux/blkdrv.h), you should write the following lines:

#include "blk.h"

This, in turn, requires that you define FOO_MAJOR to be the major number of the device you are writing in linux/major.h.

Now you need to edit blk.h. One section of blk.h, right near the top, includes definitions of macros that depend on the definition of MAJOR_NR. Add an entry to the end which looks like this:

#define DEVICE_NAME "foobar"
#define DEVICE_REQUEST do_foo_request
#define DEVICE_NR(device) (MINOR(device) >> 6)
#define DEVICE_ON(device)
#define DEVICE_OFF(device)

These are the required macros for each block device driver. There are more macros that can be defined; they are explained in the KHG.

DEVICE_NAME is the name of the driver. The AT hard drive driver uses the abbreviation “hd” in most places; for example, the request() procedure is called do_hd_request(). However, its DEVICE_NAME is “harddisk”. Similarly, the floppy driver, “fd”, has a DEVICE_NAME of “floppy”. Other drivers are even more descriptive; read blk.h and follow suit.

DEVICE_REQUEST is the request() procedure for the driver.

DEVICE_NR is used to determine the actual physical device. For example, the standard AT hard disk driver uses 64 minor devices for each physical device, so DEVICE_NR is defined as (MINOR(device)>6). The SCSI disk driver uses 16 minor device numbers per physical device, so for it, DEVICE_NR is defined as (MINOR(device)>4). If you have only one minor device number per physical device, define DEVICE_NR as (MINOR(device)).

DEVICE_ON and DEVICE_OFF are only used for devices that have to be turned on and off. The floppy driver is the only driver that uses this capability. You will most likely want to define these to be nothing at all.

All these macros, as well as many others, can be used in your driver where appropriate. blk.h includes a lot of macros, and studying how they are used in other drivers will help you use them in your own driver. I won't document them fully here, but I will briefly mention some of them to make your life easier.

DEVICE_INTR, SET_INTR, and CLEAR_INTR make support for interrupt-driven devices much easier. DEVICE_ TIMEOUT, SET_TIMER, and CLEAR_TIMER help you set limits on how long may be taken to satisfy a request.

The First Shall Be the Last

I've saved the first, and perhaps most important, thing for last. Before you can read or write a single block, the kernel has to be notified that the device exists. All device drivers are required to implement an initialization function, and there are some special requirements for block device drivers. Here is a sample idealized initialization function:

long foo_init(long mem_start, int length)
  if (register_blkdev(FOO_MAJOR,"foo", & foo_fops)) {
    printk("FOOBAR: Unable to get major %d.\n",
    return 0;
  if (!foo_exists()) {
    /* the foobar device doesn't exist */
    return 0;
  /* initialize hardware if necessary */
  /* notify user device found */
  printk("FOOBAR: Found at address %d.\n",
  /* tell buffer cache how to process requests */
  blk_dev[FOO_MAJOR].request_fn = DEVICE_REQUEST;
  /* specify the blocksize */
  blksize_size[MAJOR_NR] = 1024;

The three things here that are specific to block device drivers are:

  • register_blkdev() registers the file operations structure with the Virtual Filesystem Switch (VFS), which is the system that manages access to files.

  • blk_dev tells the buffer cache where the request procedure is.

  • blksize_size tells the buffer cache what size blocks to request.

It is worth noting that the hardware device detection and initialization, which I have denoted as foo_exists() here, is very delicate code. If you can rely on a string somewhere in the BIOS of the computer to determine whether the device exists and where it is, it's relatively easy. However, if you have to check various I/O ports, you can hang the computer by writing the wrong value to the wrong port, or even reading the wrong port. Check only well-known ports if you must check ports, and provide kernel command-line arguments for other ports. To do this, read init/main.c and add a section of your own. If you can't figure out how to do it, an explanation is forthcoming in the next version of the KHG.

Of course, none of this initialization will happen if foo_init() is never called. Add a prototype to the top of blk.h with the other prototypes, and add a call to foo_init() in ll_rw_blk.c in the blk_dev_init() function. That call should be protected by #ifdef CONFIG_FOO like the rest of the *_init() functions there, and a corresponding line should be added to the file:

bool `Foobar disk support' CONFIG_FOO y

drivers/block/Makefile should have a section added that looks like this:

OBJS := $(OBJS) foo.o
SRCS := $(SRCS) foo.c

This done, configuration should work correctly. Your device driver file does not need to have any references to CONFIG_FOO; the only specific reference to it is commented out in ll_rw_blk.c, and the makefile only builds it if it has been configured in.

Now all you have to do is write and debug your own new block device driver. I wish you the best of luck, and I hope that this whirlwind tour has given you a head start.

Other Resources

Michael K. Johnson is the editor of Linux Journal, and is also the author of the Linux Kernel Hackers' Guide (the KHG). He is using this column to develop and expand on the KHG.



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

page 3?

Anonymous's picture

This article has 3 pages, but it seems to end on page 2, because page 3 is empty.

Useful for a newbie

Sivakumar.R.J's picture

its really useful for a newbie entering into a block device driver, I am a just a beginner of it.. looking some more information regarding block driver in this forum.. thanks for the article..

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState