Putting It All Together

The above descriptions, while strictly useful as documentation, do not really show how it all gets put together to make a device driver. The following example of how to create the data structures for a device driver, for a standard PC target, are derived from the eCosPro IDE disk driver.

The first thing to do is to define the disk controllers:

static ide_controller_info_t ide_controller_info_0 = {
    ctlr:       0,
    vector:     HAL_IDE_INTERRUPT_PRI

DISK_CONTROLLER( ide_disk_controller_0, ide_controller_info_0 );

static ide_controller_info_t ide_controller_info_1 = {
    ctlr:       1,
    vector:     HAL_IDE_INTERRUPT_SEC

DISK_CONTROLLER( ide_disk_controller_1, ide_controller_info_1 );

A typical PC target has two IDE controllers, so we define two controllers. The ide_controller_info_t structure is defined by the driver and contains information needed to access the controller. In this case this is the controller number, zero or one, and the interrupt vector it uses. The DISK_CONTROLLER() macro generates a system defined controller structure and populates it with a pointer to the matching controller info structure.

The next step is to define the disk functions that will be called to perform data transfers on this driver. These functions the main part of the driver, together with the init and lookup functions and any ISR and DSR functions.


We can now start generating per-disk-channel data structures. To make this easier we define a macro, IDE_DISK_INSTANCE() to make this easier.

#define IDE_DISK_INSTANCE(_number_,_ctlr_,_dev_,_mbr_supp_)     \
static ide_disk_info_t ide_disk_info##_number_ = {              \
    num:           _number_,                                    \
    ctlr:          &ide_controller_info_##_ctlr_,               \
    dev:           _dev_,                                       \
};                                                              \
DISK_CHANNEL(ide_disk_channel##_number_,                        \
             ide_disk_funs,                                     \
             ide_disk_info##_number_,                           \
             ide_disk_controller_##_ctlr_,                      \
             _mbr_supp_,                                        \
             4                                                  \
);                                                              \
BLOCK_DEVTAB_ENTRY(ide_disk_io##_number_,                       \
             CYGDAT_IO_DISK_IDE_DISK##_number_##_NAME,          \
             0,                                                 \
             &cyg_io_disk_devio,                                \
             ide_disk_init,                                     \
             ide_disk_lookup,                                   \
             &ide_disk_channel##_number_                        \

The first thing this macro does is generate an instance of the ide_disk_info_t. This is a driver-defined structure to contain any info that does not fit in the system defined structures. In this case the important things are the number of the device on the controller, zero or one mapping to master or slave, and a pointer to the driver-defined controller structure. The DISK_CHANNEL() macro creates a disk channel object and populates it with the function list defined earlier, a pointer to the matching local info structure just defined, and a pointer to the controller it is attached to. Finally, a device table entry is created. This uses linker features to install an entry into the device table that allows the IO subsystem to locate this device.

Finally we need to instantiate all the channels that this driver will support.

IDE_DISK_INSTANCE(0, 0, 0, true);
IDE_DISK_INSTANCE(1, 0, 1, true);
IDE_DISK_INSTANCE(2, 1, 0, true);
IDE_DISK_INSTANCE(3, 1, 1, true);

Each invocation of IDE_DISK_INSTANCE() generates all the data structures needed to access each possible physical disk that may be present.

Documentation license for this page: eCosPro License