Quick introduction
An application interacts with a device driver thanks to file system functions (CreateFile
, ReadFile
, WriteFile
,...).
To identify the driver to be opened, the application needs to specify a file name to CreateFile:
* [Usual format] "XXXy:"
: with X a capital letter and y a number in [1;9] (0 is authorize to indicate the 10th index)
* [Device mount point] "\\<device_mount_point>\\XXXy:"
* [Bus mount point] "\\<bus_mount_point>\\XXXy:"
The three capital letters form a prefix that will identify the driver. The number indicates the index of the driver if several can be instanciated.
This prefix is also used by Windows to load the device driver methods. In fact, the prefix shall precede the device driver methods in driver dll:
* XXX_CreateFile
* XXX_ReadFile
* ...
All device drivers are listed in registry below HKLM\Drivers\BuiltIn with at least the following subkeys:
Key |
Description |
Prefix |
Explained above (e.g. "XXX") |
Dll |
Driver dll method to be loaded |
At system boot, Device Manager will iterate over these entries and load them. For every loaded driver, an entry will be created in HKLM\Drivers\Active.
The order of load can be specified if the driver entry specifies a key Order followed by a number that indicates when it shall be loaded (with 1 the first to be loaded)
Other optional subkeys can be used for a driver, but they won't be described here.
In the following chapters, we will create the necessary files to add a driver to our BSP. In the scope of this tutorial, we will create a driver for the DS1307 RTC chip.
Add a new catalog entry
The first step is to add a catalog entry to our BSP. To do so, either open the *.pbcxml file with Visual Studio and use the graphical interface or edit the *.pbcxml file and add the following lines:
<Bsp>
...
<BspItemId>FT5X06_TOUCH:LNI Swissgass:FT5X06_LniBSP</BspItemId>
<BspItemId>RTC_DS1307:LNI Swissgass:RTC_DS1307_LniBSP</BspItemId>
<BspItemId>DVI_Type:LNI Swissgas:DVI_Type_LniBSP</BspItemId>
...
</Bsp>
<Item Id="RTC_DS1307:LNI Swissgass:RTC_DS1307_LniBSP">
<Title>RTC driver</Title>
<Description>Real Time Clock</Description>
<Comment>Only valid for DS1307 chip</Comment>
<Type>BspSpecific</Type>
<Variable>BSP_RTC_DS1307</Variable>
<Module>rtc_ds1307.dll</Module>
<Location ConditionLocation="">Drivers\RTC</Location>
</Item>
These lines add a new driver to the catalog under Driver\RTC. If checked, this driver defines the variable BSP_RTC_DS1307
.
Hands on code : create the driver component
Create a directory for our driver under <MyBSP>\SRC\Drivers : here we create a folder named RTC. The following steps are to be done in this directory.
The most obvious file to add to our componen is makefile
. This file is always the same for all drivers so copy/paste an existing one or create it and add the following lines:
!if 0
Copyright (c) Microsoft Corporation. All rights reserved.
!endif
!if 0
Use of this source code is subject to the terms of the Microsoft end-user
license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
If you did not accept the terms of the EULA, you are not authorized to use
this source code. For a copy of the EULA, please see the LICENSE.RTF on your
install media.
!endif
#
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
# file to this component. This file merely indirects to the real make file
# that is shared by all the components of Windows CE.
#
!INCLUDE $(_MAKEENVROOT)\makefile.def
Our driver needs to be declared in registry. Create an rtc_ds1307.reg
file and the following lines:
IF BSP_RTC_DS1307
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\RTC_DS1307]
"Prefix"="RTC"
"Dll"="rtc_ds1307.dll"
"Index"=dword:1
"order"=dword:101 ; Should be loaded after I2C
ENDIF BSP_RTC_DS1307
The file structure of a WEC7 BSP requires a file named sources
in every folder that contains files to take into consideration during build. Create one with the following lines:
!if 0
;================================================================================
; RTC Driver DS1307
;================================================================================
!endif
!IF "$(BSP_RTC_DS1307)" == ""
SKIPBUILD=1
!ENDIF
TARGETNAME=rtc_ds1307
TARGETTYPE=DYNLINK
TARGETLIBS= \
$(_PLATLIB)\$(_CPUDEPPATH)\ceddk.lib \
$(_COMMONSDKROOT)\lib\$(_CPUINDPATH)\coredll.lib
SOURCES= \
rtc_ds1307.c \
Our driver will obviously need to export the stream interface driver methods. This is done with a *.def
file as follows:
LIBRARY RTC_DS1307
EXPORTS RTC_Init
RTC_Deinit
RTC_Open
RTC_Close
RTC_Read
RTC_Write
RTC_IOControl
And now, we can add some code :
//
// File: rtc_ds1307.c
//
// This file implements device driver for RTC DS1307.
//
#include "omap.h"
#include "ceddkex.h"
#include "sdk_padcfg.h"
#include "bsp_padcfg.h"
#include "bsp.h"
#include <nkintr.h>
#include <winuserm.h>
#include <pmpolicy.h>
// ==== Debug Zones ================================================================================
// simple handling: debug zones are forced with TRUE or FALSE and need a recompile to be activated
// for sophisticated handling: use macro DEBUGZONE(), DBGPARAM dpCurSettings etc.
// (see MSDN e.g. Win CE 5.0, Debug Zones)
#ifndef SHIP_BUILD
#undef ZONE_ERROR
#undef ZONE_WARN
#undef ZONE_FUNCTION
#undef ZONE_INFO
#undef ZONE_TIPSTATE
#define ZONE_ERROR DEBUGZONE(0)
#define ZONE_WARN DEBUGZONE(1)
#define ZONE_FUNCTION DEBUGZONE(2)
#define ZONE_INFO DEBUGZONE(3)
#define ZONE_TIPSTATE DEBUGZONE(4)
static DBGPARAM dpCurSettings = {
L"RTC_DS1307", {
L"Errors", L"Warnings", L"Function", L"Info",
L"IST", L"Undefined", L"Undefined", L"Undefined",
L"Undefined", L"Undefined", L"Undefined", L"Undefined",
L"Undefined", L"Undefined", L"Undefined", L"Undefined"
},
// Bitfield controlling the zones. 1 means the zone is enabled, 0 disabled
// We'll enable the Error, Warning, and Info zones by default here
1 | 1 << 1 | 1 << 2 | 1 << 3
};
#endif
//------------------------------------------------------------------------------
DWORD RTC_Init(LPCTSTR szContext, LPCVOID pBusContext)
// Called by device manager to initialize device.
{
int i;
DWORD rc = (DWORD)NULL;
UNREFERENCED_PARAMETER(pBusContext);
DEBUGMSG(ZONE_FUNCTION, (L"+RTC_Init(%s, 0x%08x)\r\n", szContext, pBusContext));
RETAILMSG(1, (L"+RTC_Init\r\n"));
cleanUp:
DEBUGMSG(ZONE_FUNCTION, (L"-RTC_Init(rc = %d\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
BOOL RTC_Deinit(DWORD context)
{
BOOL rc = FALSE;
DEBUGMSG(ZONE_FUNCTION, (L"+RTC_Deinit(0x%08x)\r\n", context));
rc = TRUE;
cleanUp:
DEBUGMSG(ZONE_FUNCTION, (L"-RTC_Deinit(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
DWORD RTC_Open(DWORD context, DWORD accessCode, DWORD shareMode)
{
UNREFERENCED_PARAMETER(context);
UNREFERENCED_PARAMETER(accessCode);
UNREFERENCED_PARAMETER(shareMode);
return context;
}
//------------------------------------------------------------------------------
BOOL RTC_Close(DWORD context)
{
UNREFERENCED_PARAMETER(context);
return TRUE;
}
//------------------------------------------------------------------------------
DWORD RTC_Read(DWORD context, LPVOID pBuffer, DWORD Count)
{
UNREFERENCED_PARAMETER(context);
UNREFERENCED_PARAMETER(pBuffer);
UNREFERENCED_PARAMETER(Count);
return 0;
}
//------------------------------------------------------------------------------
DWORD RTC_Write(DWORD context, LPCVOID pSourceBytes, DWORD NumberOfBytes)
{
UNREFERENCED_PARAMETER(context);
UNREFERENCED_PARAMETER(pSourceBytes);
UNREFERENCED_PARAMETER(NumberOfBytes);
return 0;
}
//------------------------------------------------------------------------------
BOOL RTC_IOControl(
DWORD context, DWORD code, BYTE *pInBuffer, DWORD inSize, BYTE *pOutBuffer,
DWORD outSize, DWORD *pOutSize
) {
UNREFERENCED_PARAMETER(context);
UNREFERENCED_PARAMETER(code);
UNREFERENCED_PARAMETER(pInBuffer);
UNREFERENCED_PARAMETER(inSize);
UNREFERENCED_PARAMETER(pOutBuffer);
UNREFERENCED_PARAMETER(outSize);
UNREFERENCED_PARAMETER(pOutSize);
DEBUGMSG(ZONE_INIT, (L"RTC_IOControl"));
return FALSE;
}
//------------------------------------------------------------------------------
BOOL __stdcall DllMain(HANDLE hDLL, DWORD reason, VOID *pReserved)
{
UNREFERENCED_PARAMETER(pReserved);
switch (reason) {
case DLL_PROCESS_ATTACH:
DEBUGREGISTER(hDLL);
DisableThreadLibraryCalls((HMODULE)hDLL);
break;
}
return TRUE;
}
and a header (optional):
#ifndef __RTC_DS1307_H
#define __RTC_DS1307_H
// Stream interface entry points
// Initialization of controlled hardware, setup of ISR and IST(if any),
// setup of memory access (if any)
DWORD RTC_Init(LPCTSTR szContext, LPCVOID pBusContext);
// Cleans up what Init did
BOOL RTC_Deinit(DWORD context);
// Implicitely called by CreateFile
// Opens the context for client usage
DWORD RTC_Open(DWORD context, DWORD accessCode, DWORD shareMode);
// Closes the context opened in Open
BOOL RTC_Close(DWORD context);
// Use if required : read data out of driver
DWORD RTC_Read(DWORD context, LPVOID pBuffer, DWORD Count);
// Use if required : write data to driver
DWORD RTC_Write(DWORD context, LPCVOID pSourceBytes, DWORD NumberOfBytes);
// Driver specific functionality
BOOL RTC_IOControl(
DWORD context, DWORD code, BYTE *pInBuffer, DWORD inSize, BYTE *pOutBuffer,
DWORD outSize, DWORD *pOutSize
);
#endif // __RTC_DS1307_H
Add driver to project build
The driver component is ready, we need to include it to the project. As said earlier, the file structure of a BSP requires sources
files to include files to build but also dirs
files to list the directories that will be visited during build. Open <MyBSP>\SRC\Drivers\dirs
and add an entry for our new driver.
DIRS=\
...
FT5X06\
RTC_DS1307\
WAVEDEV2\
...
For rom image creation, we need now to tell the project that it should put the driver's dll into the image.
Open platform.bib
and add the following lines:
...
IF BSP_RTC_DS1307
rtc_ds1307.dll $(_FLATRELEASEDIR)\rtc_ds1307.dll NK SHK
ENDIF
...
Finally, add the following lines to platform.reg
to integrate the component's registry settings:
...
;===============================================================================
; RTC DS1307 driver
#include "$(PLAT_DRIVERS_DIR)\RTC_DS1307\rtc_ds1307.reg"
...
You're good to start the development of the driver.