- 在BSP的Drivers目錄下,建立新驅動程式的目錄,比如MyDriver
- 修改dirs檔案,在變量DIRS中增加新目錄MyDriver
- 建立檔案Sources,内容如下:
TARGETNAME=MyDriver
RELEASETYPE=PLATFORM
TARGETTYPE=DYNLINK
DEFFILE=MyDriver.def
DLLENTRY=DllEntry
TARGETLIBS= $(_COMMONSDKROOT)/lib/$(_CPUINDPATH)/coredll.lib
SOURCES=MyDriver.c
- 建立檔案Makefile.inc,内容如下:
#
# 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
- 建立檔案MyDriver.def,内容如下:
LIBRARY MyDriver
EXPORTS XXX_Init
XXX_Deinit
XXX_Open
XXX_Close
XXX_Read
XXX_Write
XXX_Seek
XXX_PowerDown
XXX_PowerUp
XXX_IOControl
- 建立檔案MyDriver.c,内容如下:
#include <windows.h>
#include <Devload.h>
BOOL XXX_Deinit(DWORD hDeviceContext)
{
return TRUE;
}
DWORD XXX_Init(ULONG RegistryPath)
{
HKEY hKey;
RETAILMSG(1, (TEXT("XXX_Init/n")));
hKey = OpenDeviceKey((LPCTSTR) RegistryPath);
if(!hKey)
{
RETAILMSG(1, (TEXT("Failed to open devkeypath,/r/n")));
}
else
{
/* Read values from registry if needed */
RegCloseKey(hKey);
}
return TRUE;
}
BOOL WINAPI DllEntry(HINSTANCE DllInstance, ULONG Reason, LPVOID Reserved)
{
RETAILMSG(1, (TEXT("MyDriver: DllEntry/n")));
return TRUE;
}
VOID XXX_PowerUp(DWORD hDeviceContext)
{
}
VOID XXX_PowerDown(DWORD hDeviceContext)
{
}
DWORD XXX_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode)
{
return hDeviceContext;
}
BOOL XXX_Close(DWORD hOpenContext)
{
return TRUE;
}
DWORD XXX_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count)
{
return 0;
}
DWORD XXX_Write(DWORD hOpenContext, LPCVOID pSourceBytes, DWORD NumberOfBytes)
{
return 0;
}
DWORD XXX_Seek(DWORD hOpenContext, long Amount, DWORD Type)
{
return 0;
}
BOOL XXX_IOControl
(
DWORD hOpenContext,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut
)
{
BOOL RetVal = TRUE;
switch(dwCode)
{
default: RetVal = FALSE; break;
}
return RetVal;
}
- 在platform.bib或者project.bib中,加入此驅動:
MyDriver.dll $(_FLATRELEASEDIR)/MyDriver.dll NK K
- 在platform.reg或者project.reg中,設定此驅動為BuildIn類型,自動加載:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/MyDriver]
"Dll"="MyDriver.dll"
"Order"=dword:4
"Prefix"="XXX"
至此,一個沒有實作任何功能的驅動完成了,下面描述如何在驅動中使用中斷。
- 建立中斷線程函數(IST),線上程中申請并等待中斷:
static DWORD WINAPI MyInterruptThread(LPVOID p)
{
DWORD RetVal = 0;
HANDLE hEvent;
DWORD SysintrValue;
DWORD IRQ = MYDRIVER_IRQ;
/* Create an Event */
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
/* Register with the Kernel */
KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &IRQ, sizeof(DWORD), &SysintrValue, sizeof(DWORD), NULL);
RetVal = InterruptInitialize(SysintrValue, hEvent, NULL, 0);
/* Set the Thread Priority */
CeSetThreadPriority(GetCurrentThread(), 150);
while(1)
{
/* Wait for the Event to be Signaled */
RetVal = WaitForSingleObject(hEvent, 2000);
if(RetVal == WAIT_OBJECT_0)
{
/*
* Service the Interrupt
* In this case suspend the device
*/
SetSystemPowerState(NULL, POWER_STATE_SUSPEND, POWER_FORCE);
/* Tell the Kernel that the Interrupt has been Serviced */
InterruptDone(SysintrValue);
}
else if(RetVal == WAIT_TIMEOUT)
{
/*
* Optional, provide a way to stop the thread when the driver unloads
* This is optional because the driver may never unload
*/
if(StopThreads) break;
}
}
/* When and if the driver unloads and the thread exits release resources */
InterruptDisable(SysintrValue);
CloseHandle(hEvent);
KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &SysintrValue, sizeof(DWORD), NULL, 0, NULL);
return 0;
}
- 驅動Dll被加載後,系統首先調用DllEntry,随後調用XXX_Init。修改XXX_Init,加入線程啟動代碼:
HANDLE hthrd;
// Start thread
hthrd = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)MyInterruptThread,NULL,0,NULL);
// Since we don't need the handle, close it now.
CloseHandle(hthrd);
如果驅動隻需要處理一個中斷,WaitForSingleObject可以處理得很好,如果有多個中斷需要處理時,能依葫蘆畫瓢,建立多個event,每個event注冊一個中斷,然後使用WaitForMultipleObjects嗎?很遺憾,雖然WinCE支援WaitForMultipleObjects,但對于注冊到中斷的event,隻允許等待一個,考慮到中斷處理程式所要求的高性能,為了避免進入死鎖,當event數目大于1時,WaitForMultipleObjects将會失敗,GetLastError傳回參數無效的錯誤代碼(是的,如果隻有一個event,WaitForMultipleObjects仍然會成功)。
在這種情況下,一種解決方法是,建立多個IST,每個IST處理一個中斷。
此外,還有另一種更好的方法,就是把同一個event注冊到多個中斷,然後使用WaitForSingleObject等待此event,每個中斷被觸發時,event都會獲得信号:
int i;
HANDLE hEvent;
// Create an Event
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// Init all interrupt to a event
for(i=0; i<MY_INT_COUNT; i++)
{
// Register with the Kernel
KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &irqs[i], sizeof(DWORD), &intrs[i], sizeof(DWORD), NULL) ;
InterruptInitialize( intrs[i], hEvent, NULL, 0 );
}
.
.
.
.
// When and if the driver unloads and the thread exits release resources
for(i=0;i<MY_INT_COUNT;i++)
{
InterruptDisable( intrs[i]);
KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &intrs[i], sizeof(DWORD), NULL, 0, NULL);
}
CloseHandle( hEvent );
(參考了Bruce Eitman的文章,http://geekswithblogs.net/BruceEitman/Default.aspx)