天天看點

如何開發一個WinCE 6的流裝置驅動

  • 在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)

繼續閱讀