涉及版权,欲用于商业用途,务必与作者联系;
QQ:26764135
伊妹儿/麦思恩:liam7953@yahoo.com.cn
在WINCE6中,应用程序无法直接访问GPIO,而必须通过一个驱动程序,在此,我们用一个通用的流驱动来实现。
一个简单的流驱动包含如下几个部分:
XXX.CPP \\实现文件
XXX.def \\符号导出文件
makefile \\编译文件
sources \\
GPI.reg \\注册表文件,假如需要做进包里,需要增加进入工程注册表,假如动态加载,需要用程序将其写到系统中
//如下部分为源程序部分
// GPI.cpp : Defines the entry point for the DLL application.
//
#include "GPI.h"
#include <windows.h>
#include <memory.h>
#include <nkintr.h>
#include <ceddk.h>
#include <winioctl.h>
#pragma comment(lib,"ceddk.lib")
#define GIO_VENDOR CTL_CODE(FILE_DEVICE_SERIAL_PORT, 2090, METHOD_BUFFERED, FILE_ANY_ACCESS)
static UCHAR * virGpioMemBase = NULL;
/**************************************************************************
* 基础函数定义 *
**************************************************************************/
/************************************************************
* OutPortByte
*
* 向特定GPIO地址输出字节
*/
static void OutPortByte(WORD wAddr,byte bValue)
{
if(NULL != virGpioMemBase)
{
if( W83627_EFER == wAddr)
{
WRITE_PORT_UCHAR(virGpioMemBase,bValue);
}
else
{
WRITE_PORT_UCHAR(virGpioMemBase+1,bValue);
}
}
else
{
RETAILMSG(TRUE, (TEXT(">>YOU NAME-OutPortByte return for virGpioMemBase NULL\r\n")));
}
RETAILMSG(TRUE, (TEXT(">>YOU NAME-OutPortByte: Add:0x%x, Val:0x%x\r\n"),wAddr,bValue));
}
/************************************************************
* InPortByte
*
* 从特定GPIO地址读取字节
*/
static byte InPortByte(WORD wAddr)
{
byte tmpRtnVal = 0xFF;
if(NULL != virGpioMemBase)
{
if( W83627_EFER == wAddr)
{
tmpRtnVal = READ_PORT_UCHAR(virGpioMemBase);
}
else
{
tmpRtnVal = READ_PORT_UCHAR(virGpioMemBase+1);
}
}
else
{
RETAILMSG(TRUE, (TEXT(">>YOU NAME-InPortByte return for virGpioMemBase NULL\r\n")));
}
RETAILMSG(TRUE, (TEXT(">>--YOU NAME-InPortByte, Add:0x%x Val:0x%x!\r\n"),wAddr,tmpRtnVal));
return tmpRtnVal;
}
/************************************************************
* W83627Set
*
* 设定W8362 PIO A 值
*/
static void W83627Set(byte ucParaVal)
{
RETAILMSG(TRUE, (TEXT(">>++YOU NAME-W83627Set Val:0x%x!\r\n"),ucParaVal));
//enter the extended function mode,two successive writes of 0x87 must be applied to
//Extended Function Enable Registers(EFERs,i.e. 2Eh)
OutPortByte(W83627_EFER,0x87);
OutPortByte(W83627_EFER,0x87);
//CRF1(GP10-GP17 data register Default 0x00)
//if a port is programmed to be an output port,then its respective bit can be read/write
//if a port is programmed to be an input port,then its respective bit can only be read
OutPortByte(W83627_EFIR,0x07);
OutPortByte(W83627_EFDR,0x08);
//实际写值到对应的寄存器
OutPortByte(W83627_EFIR ,0xF1);
OutPortByte(W83627_EFDR ,ucParaVal);
//exit extended function mode
OutPortByte(W83627_EFER,0xAA);
Sleep(1);
}
/************************************************************
* W83627Set
*
* 读取W8362 PIO A 值
*/
static byte W83627Get()
{
byte tmpVal = 0;
//enter the extended function mode,two successive writes of 0x87 must be applied to
//Extended Function Enable Registers(EFERs,i.e. 2Eh)
OutPortByte(W83627_EFER,0x87);
OutPortByte(W83627_EFER,0x87);
//Configurate the configuration registers
//configure logical device 7(gp10-gp17),configuration register CRF0,CRF1,CRF2
//select logical device 7
OutPortByte(W83627_EFIR,0x07);
OutPortByte(W83627_EFDR,0x08);
//CRF1(GP10-GP17 data register Default 0x00)
//if a port is programmed to be an output port,then its respective bit can be read/write
//if a port is programmed to be an input port,then its respective bit can only be read
OutPortByte(W83627_EFIR,0xF1);
tmpVal = InPortByte(W83627_EFDR);
//exit extended function mode
OutPortByte(W83627_EFER,0xAA);
Sleep(1);
RETAILMSG(TRUE, (TEXT(">>++YOU NAME-W83627Get4 Val:0x%x!\r\n"),tmpVal));
return (byte)(tmpVal);
}
/************************************************************
* W83627VendorIdGet
*
* 读取W8362 部分厂家编号
*/
static byte W83627VendorIdGet()
{
byte tmpVal = 0;
//enter the extended function mode,two successive writes of 0x87 must be applied to
//Extended Function Enable Registers(EFERs,i.e. 2Eh)
OutPortByte(W83627_EFER,0x87);
OutPortByte(W83627_EFER,0x87);
//Configurate the configuration registers
OutPortByte(W83627_EFER,0x20);
tmpVal = InPortByte(W83627_EFDR);
//exit extended function mode
OutPortByte(W83627_EFER,0xAA);
Sleep(1);
RETAILMSG(TRUE, (TEXT(">>++YOU NAME-W83627VendorIdGet:0x%x\r\n"),tmpVal));
return (byte)(tmpVal);
}
/************************************************************
* W83627GPIInit
*
* 初始化W83627GPI A 相关的寄存器
*/
static void W83627GPIInit()
{
//enter the extended function mode,two successive writes of 0x87 must be applied to
//Extended Function Enable Registers(EFERs,i.e. 2Eh)
OutPortByte(W83627_EFER,0x87);
OutPortByte(W83627_EFER,0x87);
//Configurate the configuration registers
OutPortByte(W83627_EFIR ,0x2a); //EFIR write control register index to EFIR
OutPortByte(W83627_EFDR ,0x01); //GPIO20 119S
//Configurate the configuration registers
OutPortByte(W83627_EFIR ,0x2b); //EFIR write control register index to EFIR
OutPortByte(W83627_EFDR ,0xff); //GPIO21~GPIO27
//configure logical device 7(gp10-gp17),configuration register CRF0,CRF1,CRF2
//select logical device 7
OutPortByte(W83627_EFIR,0x07);
OutPortByte(W83627_EFDR,0x08);
OutPortByte(W83627_EFIR,0x30);
OutPortByte(W83627_EFDR,0x01);
//CRF0(GP10-GP17 I/O selection register Default 0xff)
//when set to a ’1’, respective GPIO port is programmed as an input port
//when set to a ’0’, respective GPIO port is programmed as an output port
OutPortByte(W83627_EFIR,0xF0);
OutPortByte(W83627_EFDR,0x00);
//GPIO10,11,12,13输入,14,15,16,17,输出
//CRF2(GP10-GP17 inversion register Default 0x00)
//when set to a ’1’,the imcoming/outgoing port value is inverted
//when set to a ’0’,the imcoming/outgoing port value is the same as in data register
OutPortByte(W83627_EFIR,0xF2);
OutPortByte(W83627_EFDR,0x00);
//CRF1(GP10-GP17 data register Default 0x00)
//if a port is programmed to be an output port,then its respective bit can be read/write
//if a port is programmed to be an input port,then its respective bit can only be read
OutPortByte(W83627_EFIR,0xF1);
OutPortByte(W83627_EFDR,0x00);
//exit extended function mode
OutPortByte(W83627_EFER,0xAA);
Sleep(10);
RETAILMSG(TRUE, (TEXT(">>++YOU NAME-W83627GPIInit\r\n")));
}
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
default:
break;
}
return TRUE;
}
GPI_API DWORD GPI_Init(LPCTSTR pContext,DWORD dwBusContext)
{
PHYSICAL_ADDRESS IoAddress;
IoAddress.LowPart = W83627_EFER;//硬件地址
IoAddress.HighPart = 0;
virGpioMemBase = ( UCHAR *)MmMapIoSpace( IoAddress , 2 , FALSE );
if(NULL != virGpioMemBase)
{
RETAILMSG(TRUE, (TEXT(">>YOU NAME-OutPortByte:MmMapIoSpace return:0x%x\r\n"),virGpioMemBase));
}
else
{
RETAILMSG(TRUE, (TEXT(">>YOU NAME-OutPortByte,MmMapIoSpace return NULL\r\n")));
return (FALSE);
}
if(W83627_VENDOR != W83627VendorIdGet())
{
RETAILMSG(TRUE, (_T(">>++YOU NAME-ERROR::W83627VendorIdGet Check failed\r\n")));
return (FALSE);
}
W83627GPIInit();
RETAILMSG(TRUE, (TEXT(">>--YOU NAME-GPI_Init\r\n")));
return(TRUE);
}
GPI_API BOOL GPI_Deinit(DWORD hDeviceContext)
{
if(NULL != virGpioMemBase)
{
MmUnmapIoSpace( (PVOID)virGpioMemBase , 2);
virGpioMemBase = NULL;
}
RETAILMSG(TRUE, (TEXT(">>++YOU NAME-GPI_Deinit\r\n")));
return (TRUE);
}
GPI_API DWORD GPI_Open (DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode)
{
RETAILMSG(TRUE, (TEXT(">>++YOU NAME-GPI_Open\r\n")));
return(TRUE);
}
GPI_API BOOL GPI_Close(DWORD hOpenContext)
{
RETAILMSG(TRUE, (TEXT(">>++YOU NAME-GPI_Close\r\n")));
return TRUE;
}
GPI_API DWORD GPI_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count)
{
BYTE * pdatabuf = NULL;
pdatabuf = (BYTE * )pBuffer;
*pdatabuf = W83627Get();
RETAILMSG(TRUE, (TEXT(">>--YOU NAME-GPI_Read Val:0x%x\r\n"),*pdatabuf));
return (TRUE);
}
GPI_API DWORD GPI_Write(DWORD hOpenContext,LPCVOID pBuffer,DWORD Count)
{
BYTE* pdatabuf = NULL;
pdatabuf = (BYTE*)pBuffer;
W83627Set(*pdatabuf);
RETAILMSG(TRUE, (TEXT(">>--YOU NAME-GPI_Write Val:0x%x\r\n"),*pdatabuf));
return (TRUE);
}
//======================================================================
// ANY_Seek - Called when SetFilePtr called
//
GPI_API DWORD GPI_Seek (DWORD hOpenContext, long Amount, WORD Type)
{
RETAILMSG(TRUE, (TEXT(">>--YOU NAME-GPI_Seek\r\n")));
return (TRUE);
}
//======================================================================
// ANY_IOControl - Called when DeviceIocontrol called
//
GPI_API BOOL GPI_IOControl(DWORD hOpenContext,DWORD dwCode,PBYTE pBufIn,
DWORD dwLenIn,PBYTE pBufOut,DWORD dwLenOut,PDWORD pdwActualOut)
{
BOOL bError = FALSE;
switch(dwCode)
{
case GIO_VENDOR:
*(BYTE*)pBufOut = W83627VendorIdGet();
RETAILMSG(TRUE, (TEXT(">>--YOU NAME-GPI_IOControl-Vendor Read, Val:0x%x\r\n"),*(BYTE*)pBufOut));
break;
default:
break;
}
RETAILMSG(TRUE, (TEXT(">>--YOU NAME-GPI_IOControl\r\n")));
return bError;
}
//======================================================================
// ANY_PowerDown - Called when system suspends
//
GPI_API void GPI_PowerDown (DWORD hDeviceContext)
{
RETAILMSG(TRUE, (TEXT(">>++YOU NAME-GPI_PowerDown\r\n")));
return;
}
//======================================================================
// ANY_PowerUp - Called when resumes
//
GPI_API void GPI_PowerUp (DWORD hDeviceContext)
{
RETAILMSG(TRUE, (TEXT(">>++YOU NAME-GPI_PowerUp\r\n")));
return;
}
//如下部分为函数导出部分
LIBRARY GPI
EXPORTS
GPI_Init
GPI_Deinit
GPI_Open
GPI_Close
GPI_Read
GPI_Write
GPI_Seek
GPI_IOControl
GPI_PowerDown
GPI_PowerUp
//MAKE file的实现比较简单,和其他的内容是一样的
!INCLUDE $(_MAKEENVROOT)\makefile.def
//source文件实现
RELEASETYPE=PLATFORM
TARGETDEFNAME=GPI
DEFFILE=$(TARGETDEFNAME).def ##指定DLL文件导出接口函数
TARGETNAME=GPI
TARGETTYPE=DYNLINK
DLLENTRY=DllMain ##DLL入口地址
SOURCES= \
XXX.cpp \
CDEFINES=$(CDEFINES) -DGPI_EXPORTS
TARGETLIBS= \
$(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\coredll.lib \
$(_SYSGENOAKROOT)\lib\$(_CPUINDPATH)\ceddk.lib
将如上几个文件放置到WINCE的源代码目录下面,然后编译,就可以实现GPIO操作的流驱动了。