O'Reilly logo

Linux Device Drivers, Second Edition by Alessandro Rubini, Jonathan Corbet

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

The Header File blk.h

All block drivers should include the header file <linux/blk.h>. This file defines much of the common code that is used in block drivers, and it provides functions for dealing with the I/O request queue.

Actually, the blk.h header is quite unusual, because it defines several symbols based on the symbol MAJOR_NR, which must be declared by the driver before it includes the header. This convention was developed in the early days of Linux, when all block devices had preassigned major numbers and modular block drivers were not supported.

If you look at blk.h, you’ll see that several device-dependent symbols are declared according to the value of MAJOR_NR, which is expected to be known in advance. However, if the major number is dynamically assigned, the driver has no way to know its assigned number at compile time and cannot correctly define MAJOR_NR. If MAJOR_NR is undefined, blk.h can’t set up some of the macros used with the request queue. Fortunately, MAJOR_NR can be defined as an integer variable and all will work fine for add-on block drivers.

blk.h makes use of some other predefined, driver-specific symbols as well. The following list describes the symbols in <linux/blk.h> that must be defined in advance; at the end of the list, the code used in sbull is shown.

MAJOR_NR

This symbol is used to access a few arrays, in particular blk_dev and blksize_size. A custom driver like sbull, which is unable to assign a constant value to the symbol, should #define it to the variable holding the major number. For sbull, this is sbull_major.

DEVICE_NAME

The name of the device being created. This string is used in printing error messages.

DEVICE_NR(kdev_t device)

This symbol is used to extract the ordinal number of the physical device from the kdev_t device number. This symbol is used in turn to declare CURRENT_DEV, which can be used within the request function to determine which hardware device owns the minor number involved in a transfer request.

The value of this macro can be MINOR(device) or another expression, according to the convention used to assign minor numbers to devices and partitions. The macro should return the same device number for all partitions on the same physical device—that is, DEVICE_NR represents the disk number, not the partition number. Partitionable devices are introduced later in this chapter.

DEVICE_INTR

This symbol is used to declare a pointer variable that refers to the current bottom-half handler. The macros SET_INTR(intr) and CLEAR_INTR are used to assign the variable. Using multiple handlers is convenient when the device can issue interrupts with different meanings.

DEVICE_ON(kdev_t device) , DEVICE_OFF(kdev_t device)

These macros are intended to help devices that need to perform processing before or after a set of transfers is performed; for example, they could be used by a floppy driver to start the drive motor before I/O and to stop it afterward. Modern drivers no longer use these macros, and DEVICE_ON does not even get called anymore. Portable drivers, though, should define them (as empty symbols), or compilation errors will result on 2.0 and 2.2 kernels.

DEVICE_NO_RANDOM

By default, the function end_request contributes to system entropy (the amount of collected “randomness”), which is used by /dev/random. If the device isn’t able to contribute significant entropy to the random device, DEVICE_NO_RANDOM should be defined. /dev/random was introduced in Section 9.3 in Chapter 9, where SA_SAMPLE_RANDOM was explained.

DEVICE_REQUEST

Used to specify the name of the request function used by the driver. The only effect of defining DEVICE_REQUEST is to cause a forward declaration of the request function to be done; it is a holdover from older times, and most (or all) drivers can leave it out.

The sbull driver declares the symbols in the following way:

#define MAJOR_NR sbull_major /* force definitions on in blk.h */
static int sbull_major; /* must be declared before including blk.h */

#define DEVICE_NR(device) MINOR(device)  /* has no partition bits */
#define DEVICE_NAME "sbull"              /* name for messaging */
#define DEVICE_INTR sbull_intrptr        /* pointer to bottom half */
#define DEVICE_NO_RANDOM                 /* no entropy to contribute */
#define DEVICE_REQUEST sbull_request
#define DEVICE_OFF(d) /* do-nothing */

#include <linux/blk.h>

#include "sbull.h"        /* local definitions */

The blk.h header uses the macros just listed to define some additional macros usable by the driver. We’ll describe those macros in the following sections.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required