工具: PB
过程:
1、 在PB中新建工程:File -> New Project or File Name… -> WCE Dynamic~Link Library -> (Enter your project name, for example: “MyDriver”) -> (choose the kind of windows CE dll , there are three choices: “An empty project” to create a new project with nothing; “A simple Windows CE.net DLL project ” to create a simple DLL project with the entry points ; “A DLL that exports some symbols” to create a project with some output functions.) An empty project -> Finish.
2、 完成流接口驱动程序必须有的接口函数。首先选择一个设备文件名前缀用于表示这个流接口驱动程序的类别,设备文件名是由三个大字字母、一个数字和冒号组成的,例如:“COM1:”、“FDS1:”都是合法的,选择“AAA”作为设备文件名前缀。所有接口函数的代码如下:
#include <windows.h>
#include <tchar.h>
#include <smbus.h>
#include "platform.h"
#include "bceddk.h"
#define BUFSIZE 256
#define KEYADDR *((PWORD)0xB9000000)
WCHAR achBuffer[BUFSIZE];
DWORD dwAAASysIntr;
HANDLE hAAAInterruptEvent;
HANDLE hAAAInterruptThread;
enum {
IOCTL_SMBUS_READDATA = 0x80002000, // some arbirary base
IOCTL_SMBUS_WRITEDATA
};
BOOL WINAPI DllEntryPoint(HANDLE hinstDLL,
DWORD dwReason,
LPVOID lpvReserved)
{
switch(dwReason) {
case DLL_PROCESS_ATTACH:
RETAILMSG(1, (TEXT("STRINGS:DLL_PROCESS_ATTACH/n")));
break;
case DLL_THREAD_ATTACH:
RETAILMSG(1, (TEXT("STRINGS:DLL_THREAD_ATTACH/n")));
break;
case DLL_THREAD_DETACH:
RETAILMSG(1, (TEXT("STRINGS:DLL_THREAD_DETACH/n")));
break;
case DLL_PROCESS_DETACH:
RETAILMSG(1, (TEXT("STRINGS:DLL_PROCESS_DETACH/n")));
break;
#ifdef UNDER_CE
case DLL_PROCESS_EXITING:
RETAILMSG(1, (TEXT("STRINGS:DLL_PROCESS_EXITING/n")));
break;
case DLL_SYSTEM_STARTED:
RETAILMSG(1, (TEXT("STRINGS:DLL_SYSTEM_STARTED/n")));
break;
#endif
}
return TRUE;
}
DWORD ThreadProc(PVOID pArg)
{
DWORD dw;
WORD nKey;
int i;
BYTE bVk = 'A';
while (1) {
dw = WaitForSingleObject(hAAAInterruptEvent, INFINITE);
switch(dw) {
case WAIT_OBJECT_0:
nKey = KEYADDR;
RETAILMSG(1, (TEXT("AAA9554: psmPCA9554->Data[0] = X/r/n"), nKey));
for (i = 0; i < 7; i++)
{
if (!(nKey & (1 << i)))
{
bVk = 'A' + i;
keybd_event(bVk, 0, 0, 0);
//keybd_event(bVk, 0, KEYEVENTF_KEYUP, 0);
break;
}
}
ResetEvent(hAAAInterruptEvent);
InterruptDone(dwAAASysIntr);
break;
}
}
return 1;
}
DWORD AAA_Init(DWORD dwContext)
{
DWORD dwRet = 0;
DWORD dwAAAthreadID;
int x = 0;
RETAILMSG(1, (TEXT("MYSTRINGS:AAA_Init/n")));
// 初始化驱动程序
memset(achBuffer, 0, BUFSIZE * sizeof(WCHAR));
// 返回一个不为零的数
dwRet = 1;
dwAAASysIntr = InterruptConnect(Internal, 0, HWINTR_GPIO7, 0);
if (SYSINTR_NOP == dwAAASysIntr) {
RETAILMSG(1, (TEXT("AAA9554: Can't allocate AAA9554 SYSINTR/r/n")));
goto ErrorReturn;
}
hAAAInterruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL == hAAAInterruptEvent) {
RETAILMSG(1, (TEXT("AAA9554: Can't create AAA9554 interrupt event/r/n")));
goto ErrorReturn;
}
hAAAInterruptThread = CreateThread(NULL, 0, ThreadProc, &x, CREATE_SUSPENDED, &dwAAAthreadID);
if (NULL == hAAAInterruptThread) {
RETAILMSG(1, (TEXT("AAA9554: Call to CreateThread failed/r/n")));
goto ErrorReturn;
}
CeSetThreadPriority(hAAAInterruptThread, 145);
if (!InterruptInitialize(dwAAASysIntr, hAAAInterruptEvent, NULL, 0)) {
RETAILMSG(1, (TEXT("AAA9554: Call to InterruptInitialize failed/r/n")));
goto ErrorReturn;
}
ResumeThread(hAAAInterruptThread);
return dwRet;
ErrorReturn:
dwRet = 0;
return dwRet;
}
BOOL AAA_Deinit(DWORD hDeviceContext)
{
BOOL bRet = TRUE;
RETAILMSG(1, (TEXT("MYSTRINGS:AAA_Deinit/n")));
return bRet;
}
DWORD AAA_Open(DWORD hDeviceContext,
DWORD AccessCode,
DWORD ShareMode)
{
DWORD dwRet = 0;
RETAILMSG(1, (TEXT("MYSTRINGS:AAA_Open/n")));
// 必须返回一个不为空的句柄
dwRet = 1;
return dwRet;
}
BOOL AAA_Close(DWORD hOpenContext)
{
BOOL bRet = TRUE;
RETAILMSG(1, (TEXT("MYSTRINGS:AAA_Close/n")));
return bRet;
}
BOOL AAA_IOControl(DWORD hOpenContext,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut)
{
BOOL bRet = TRUE;
RETAILMSG(1, (TEXT("MYSTRINGS:AAA_IOControl/n")));
return bRet;
}
void AAA_PowerDown(DWORD hDeviceContext)
{
RETAILMSG(1, (TEXT("MYSTRINGS:AAA_PowerDown/n")));
}
void AAA_PowerUp(DWORD hDeviceContext)
{
RETAILMSG(1, (TEXT("MYSTRINGS:AAA_PowerUp/n")));
}
DWORD AAA_Read(DWORD hOpenContext,
LPVOID pBuffer,
DWORD Count)
{
DWORD dwRet = 0;
RETAILMSG(1, (TEXT("MYSTRINGS:AAA_Read/n")));
// 确定读取的字节大小读取数据
DWORD cbBuffer = wcslen(achBuffer);
dwRet = min(cbBuffer, Count);
wcsncpy((LPWSTR)pBuffer, achBuffer, dwRet);
// 返回实际读取的字节数
return dwRet;
}
DWORD AAA_Seek(DWORD hOpenContext,
long Amount,
WORD Type)
{
DWORD dwRet = 0;
RETAILMSG(1, (TEXT("MYSTRINGS:AAA_Seek/n")));
return dwRet;
}
DWORD AAA_Write(DWORD hOpenContext,
LPCVOID pBuffer,
DWORD Count)
{
DWORD dwRet = 0;
RETAILMSG(1, (TEXT("MYSTRINGS:AAA_Write/n")));
// 确定实际要写入字节的大小,写入数据
dwRet = min(BUFSIZE, Count);
wcsncpy(achBuffer, (LPWSTR)pBuffer, dwRet);
// 返回实际写入的字节数
return dwRet;
}
3、 编写DEF文件
用记事本创建一个文件名为“AAA.def”的文件,然后把需要导出的接口函数添加进入。
LIBRARY MyDriver
EXPORTS AAA_Init
AAA_PowerUp
AAA_PowerDown
AAA_Deinit
AAA_Open
AAA_Close
AAA_Read
AAA_Write
AAA_Seek
AAA_IOControl
EXPORTS段后面列出要从DLL中输出的函数的名称。在LIBRARY后面必须加上要编译文件的实际名。
4、 编写注册表:我们希望驱动程序在系统启动的时候能够自动运行,所以在“HKEY_LOCAL_MACHINE/Drivers/BuiltIn/”下面添加一个自己的注册表项。设备前缀为“AAA”,索引从1开始,驱动程序的文件名为“MyDriver.dll”,根据以上内容编写注册表为:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/AAA]
"Prefix"="AAA"
"Dll"="MyDriver.dll"
"Index"=dword:1
"Order"=dword:0
编写注册表有两种方式:直接修改PB下面的REG文件,自己写一个注册表文件通过添加组件的方式添加到内核中。
5、 编写CEC文件:有了驱动程序和注册表还不能够正确运行,因为它还没有被加入到CEC内核中,添加一个文件到定制的内核中的方法有两种:一是更改BIB文件,另一种是做一个CEC文件添加到PB中。编写CEC文件的方法如下:
在PB中:Tools -> CEC Editor… -> In the “CEC 文件编辑器” -> Catalog 右键选择“Insert Feature Group…”-> name: MyDriver -> Group: Self Driver -> OK。
在这个基础上再加入一个“Feature”,“Build Method”主要完成对定制内核的注册表部分的修改,“BIB File”负责把编译完成的“MyDriver.dll”文件添加到系统内核中去。
步骤:右键“MyDriver”-> Insert Catalog Item … -> General标签下: name: MyDriver -> Variables标签下: Name: MODULE_NAME, Value: MyDriver.dll -> Comatibility标签下 选择CPU 。 保存为“MyDriver.cec”。
6、 在PB下: File -> Manage Catalog Features -> choose the CEC file you create just now: MyDriver.cec -> press “Import” ->OK 。
7、 在Platform.bib 和 Platform.reg中把 DLL和注册表加进去:
Platform.reg中添加:
#include "$(DRIVERS_DIR)/MyDriver/MyDriver.reg"
Platform.bib中添加:
MyDriver.dll $(_FLATRELEASEDIR)/MyDriver.dll NK SH