Drivers

Drivers are a set of functions that encapsulate the interactions with particular pieces of hardware. There is usually at least one driver for each hardware type such as USB, Serial, Ethernet, etc.

To help make driver code resusable drivers typically have a common interface using the same basic commands. The commands are:

  • Init - Initialize the driver.
  • Open - Get a handle to a session or context with the driver.
  • Close - Close the session.
  • Read - Read data from the device.
  • Write - Write data to the device.
  • Ioctl - Send a command to the driver.

Rational

  • Very flexible
  • Low overhead
  • Load binaries
  • Very compatible

Problems C++

  • Virtual table layout
    • Sensitive to the order in the declaration
    • Shouldn’t change an interface once it been publish
  • C++ runtime
  • Object life time and ownership
  • C++ spec ambiguity (double check)
  • Compiler differences

Driver Setup

Define a handle for internal use.

typedef struct
{
    INT8U DrvIndex;         // index of driver list for this device
    INT8U DevIndex;         // index of device within driver
    OS_EVENT *Event;        // Handle's semaphore
    INT8U RefCount;         // reference count for Handle
} OSDRV_HANDLE_INTERNAL, *POSDRV_HANDLE_INTERNAL;

Device name link list

struct _OSDRV_NAME;
typedef struct _OSDRV_NAME
{
    char *pName;                 // name of device
    struct _OSDRV_NAME *pNext;   // link to next name
} OSDRV_NAME, *POSDRV_NAME;

Configuration table for driver initialization.

Exclusive means that the driver model will only give the driver one request at a time per handle. A driver that only wants to handle one request per device at a time should set Exclusive when it registers and only allow one Open per device

typedef struct
{
    INT8U Exclusive;        // TRUE, device accepts only one request at a time
    OSDRV_NAME Name;        // device name, linked list
} OSDRV_CONFIG, *POSDRV_CONFIG;

Dispatch function entry points for a driver.

typedef struct _OSDRV_DISPATCH
{
    POSDRV_INIT pInit;      // Initialization function
    POSDRV_OPEN pOpen;      // Open function
    POSDRV_CLOSE pClose;    // Close function
    POSDRV_READ pRead;      // Read function
    POSDRV_WRITE pWrite;    // Write function
    POSDRV_IOCTL pIoctl;    // Ioctl function
} OSDRV_DISPATCH, *POSDRV_DISPATCH;

The table of drivers to be supported in this build create this table, initializing only the Dispatch.pInit item and pass to OSDRV_Init() on startup.

typedef struct
{
    OSDRV_DISPATCH Dispatch;        // dispatch table for driver
    OSDRV_CONFIG Config;            // configuration of device
    PVOID pContext;                         // context for driver, by Handle
    INT8U Initialized;                      // is device initialized
    INT8U RefCount;                         // reference count for driver
} OSDRV_DRIVER_ENTRY, *POSDRV_DRIVER_ENTRY;

Prototypes for applications to use. These are the functions the code calls when it wants to use a driver. Each driver defines these functions.

HANDLE Open(char *pName, INT8U Flags);

INT8U Close(HANDLE H);

INT8U Read(HANDLE H, PVOID pBuffer, INT32U* pLength);

INT8U Write(HANDLE H, PVOID pBuffer, INT32U* pLength);

INT8U Ioctl(HANDLE H, INT8U Control, PVOID pBuffer, INT32U* pLength);

Using the Drivers

Create the driver table. Only the Init functions need to be set. The Init functions will fill in the rest of the information themselves.

This table can be defined as a global to make it easy to access from anywhere in the code.

OSDRV_DRIVER_ENTRY DriverTable[] =
{
    // Init Config, Context Initialized, RefCount
    { { Spi_Init, NULL, NULL, NULL, NULL, NULL }, { 0 }, NULL, FALSE, 0 },
    { { Mp3_Init, NULL, NULL, NULL, NULL, NULL }, { 0 }, NULL, FALSE, 0 }
    // add additional drivers here
};

Allocate a buffer to use in sending data to the MP3 driver.

#define MP3BUFFERSIZE   256
INT8U buffer[MP3BUFFERSIZE];

Initialize the driver sub-system. Called from your main startup task.

err = OSDRV_SubsysInit(DriverTable, DRIVER_COUNT);

Get handles to the SPI and MP3 drivers.

hSpi = Open(SPI_DRV1, OSDRV_WRITE | OSDRV_EXCLUSIVE);

hMp3 = Open(MP3_DRV0, OSDRV_WRITE | OSDRV_EXCLUSIVE);

Tell the MP3 driver which SPI port driver to use.

length = sizeof(HANDLE);
err = Ioctl(hMp3, IOCTL_MP3_SET_SPI, &hSpi, &length);

Table Of Contents

Previous topic

uCOS Memory Functions

Next topic

Creating a Driver

This Page