在上次的边做边学中,我们了解到了内置的设备驱动程序的架构,因为各种不同类别的内置驱动程序要实现不同的接口,因此在实现起来就非常有针对性,也不利于演示。这次我们继续了解另一种驱动程序——流接口驱动程序的特点及其实现方法。 流接口驱动程序是在应用程序层采用标准的文件操作APIS来调用设备的,最常见的就是串口,我们可以使用CreateFile()函数来打开一个串口,然后通过ReadFile(),WriteFile()函数来读写串口,很显然,串口就是一种流接口的驱动程序。这类驱动程序的特点就是有着统一的接口函数,设备端一般都较简单,以数据提供者为主。 标准的流接口是如下的一组函数,我们先来看一下这组函数的基本外观: 1、HANDLE XXX_Init(LPCTSTR pContext,LPCVOID lpvBusContext); 这个函数是在设备管理程序通过ActiveDeviceEx()函数激活设备时被系统调用的。它的主要功能是初始化驱动程序中用到的资源,对I/O地址空间和内存进行映射等。 2、BOOL XXX_Deinit(DWORD hDeviceContext); 这个函数是在设备管理程序通过DeactivateDevice()函数卸载设备时被系统调用的,它的主要功能是回收驱动程序中用到的资源。 3、DWORD XXX_Open(DWORD hDeviceContext,DWORD AccessCode,DWORD ShareMode); 这个函数是在应用程序通过CreateFile()函数打开设备时调用的。 4、BOOL XXX_Close(DWORD hOpenContext); 这个函数是在应用程序通过CloseHandle()函数关闭句柄时调用的。 5、DWORD XXX_Read(DWORD hOpenContext,LPVOID pBuffer,DWORD Count); 这个函数是在应用程序通过ReadFile()函数读取设备时调用的。 6、DWORD XXX_Write(DWORD hOpenContext,LPCVOID pBuffer,DWORD Count); 这个函数是在应用程序通过WriteFile()函数向设备写入数据时调用的。 7、DWORD XXX_IOControl(DWORD hOpenContext,DWORD dwCode,PBYTE pBufIn,DWORD dwLenIn,PBYTE pBufOut,DWORD dwLenOut,PDWORD pdwActualOut); 这个函数是在应用程序通过DeviceIOControl()函数向设备发送控制字时调用的。 8、void XXX_PowerUp(DWORD hDeviceContext); 这个函数是在向设备恢复供电的时候调用的。 9、void XXX_PowerDown(DWORD hDeviceContext); 这个函数是在设备断电的时候调用的。
上述函数中的XXX部分是在注册表中注册此设备驱动程序的时候Perfix注册表项的值。例如串口,则用Com,并口则用LTP等等。只要一个DLL中针对特定设备实现了上述接口并且正确在注册表中注册,那么就可以在程序中通过那些文件API函数来访问此设备。下面我们就一起在PB5中按上述接口模拟一个设备。设备的名字就叫做TTT吧。 运行PB5,打开上次做的平台,在文件菜单中执行"New Project or File"命令,新建一个"WCE Dynamic-Link Library"项目,输入项目名字为"Test"。在向导的第一步中输入必要的信息(此处不输也可以,这些信息可供向导自动生成一个README.TXT文件,不过还是写上好,以免以后忘了),在下一步中选择一个空项目,完成。 在新的源程序文件中输入以下程序: // test.cpp : Defines the entry point for the DLL application. // #include "stdafx.h" #include "memory.h" #include "windows.h" HANDLE* hDevice; #define BUFSIZE 256 WCHAR buffer[BUFSIZE]; BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } HANDLE TTT_Init(LPCTSTR pContext,LPCVOID lpvBusContext) { hDevice=(HANDLE*)LocalAlloc(LPTR,sizeof(HANDLE)); memset(buffer,0,sizeof(WCHAR)*BUFSIZE); return hDevice; } BOOL TTT_Deinit(DWORD hDeviceContext) { LocalFree(hDevice); return TRUE; } DWORD TTT_Open(DWORD hDeviceContext,DWORD AccessCode,DWORD ShareMode) { if (!hDeviceContext) return FALSE; return TRUE; } BOOL TTT_Close(DWORD hOpenContext) { if (!hOpenContext) return FALSE; return TRUE; } DWORD TTT_Read(DWORD hOpenContext,LPVOID pBuffer,DWORD Count) { DWORD dwret=min(BUFSIZE,Count); wcsncpy((LPWSTR)pBuffer,buffer,dwret); return dwret; }; DWORD TTT_Write(DWORD hOpenContext,LPCVOID pBuffer,DWORD Count) { DWORD dwret=min(BUFSIZE,Count); wcsncpy(buffer,(LPWSTR)pBuffer,dwret); return dwret; } DWORD TTT_IOControl(DWORD hOpenContext,DWORD dwCode,PBYTE pBufIn, DWORD dwLenIn,PBYTE pBufOut,DWORD dwLenOut,PDWORD pdwActualOut) { return TRUE; } void TTT_PowerUp(DWORD hDeviceContext) { return; } void TTT_PowerDown(DWORD hDeviceContext) { return; } 编译,然后编译该test文件夹下的test.def文件,将这些实现的接口函数导出: LIBRARY TEST.DLL EXPORTS TTT_Init TTT_Deinit TTT_Open TTT_Close TTT_PowerUp TTT_PowerDown TTT_IOControl TTT_Read TTT_Write 同时编辑此文件夹下的test.reg文件,加入必要的注册表项: [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\test] "DeviceArrayIndex"=dword:0 "Prefix"="TTT" "Dll"="test.Dll" "Order"=dword:20
好了,一个TTT设备的流接口驱动就写好了,从中可以看到,在写驱动的时候比PB4要更加清晰,在源程序文件夹中的DEF文件,REG文件,BIB文件,DB文件,DAT文件和编译链接时需要的BAT文件都被PB生成好了,开发人员只要作些必要的修改即可以,非常方便。 接下来,为了测试我们的驱动程序是否可以正常工作,还需要写一个测试程序,再次为平台新建一个WCE应用程序项目TestTTT,写入如下代码并编译为EXE文件: #include "stdafx.h" #include "windows.h" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. HANDLE handle=CreateFile(_T("TTT1:"),GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING,0,NULL); ASSERT(handle); DWORD ret=0; TCHAR* pstr=_T("This is a TEST of TTT Driver"); WriteFile(handle,pstr,(_tcslen(pstr)+1)*sizeof(TCHAR),&ret,NULL); TCHAR ReadStr[256]; memset(ReadStr,0,sizeof(TCHAR)*256); ret=0; ReadFile(handle,ReadStr,sizeof(ReadStr),&ret,NULL); MessageBox(NULL,ReadStr,_T("Test"),MB_OK); CloseHandle(handle); return 0; } 好了,一切准备就绪,重新编译平台并下载到设备上运行,在Windows文件夹(修改文件夹选项,把所有的复选框全去掉才能看到隐藏的和系统文件)下可以找到test.dll文件和TestTTT.exe文件,运行后者,结果如图:

很简单吧,你只要在上述的接口中访问你的设备端口读写数据就可以了,我只是举个例子,希望能对你有所启发,对于驱动程序部分的内容,就先告一段落吧,继续关注后续文章吧! |