======= 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. .. code-block:: c 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 .. code-block:: c 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 .. code-block:: c 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. .. code-block:: c 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. .. code-block:: c 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. .. code-block:: c 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. .. code-block:: c 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. .. code-block:: c #define MP3BUFFERSIZE 256 INT8U buffer[MP3BUFFERSIZE]; Initialize the driver sub-system. Called from your main startup task. .. code-block:: c err = OSDRV_SubsysInit(DriverTable, DRIVER_COUNT); Get handles to the SPI and MP3 drivers. .. code-block:: c 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. .. code-block:: c length = sizeof(HANDLE); err = Ioctl(hMp3, IOCTL_MP3_SET_SPI, &hSpi, &length);