功能描述:按下Kn的时候LEDn亮(n=1..4)
一、 驱动程序(KeyLed.cpp)
#include <windows.h>
//#include <ceddk.h>
#include <nkintr.h>
//#include <oalintr.h>
#include <pm.h>
#include "pmplatform.h"
#include "Pkfuncs.h"
#include "s2440.h"
volatile IOPreg *s2440IOP = (IOPreg *)IOP_BASE;
volatile INTreg *s2440INT = (INTreg *)INT_BASE;
HANDLE KeyThread;
HANDLE KeyEvent;
UINT32 g_KeySysIntr[4];
void Virtual_Alloc(); // Virtual allocation
DWORD UserKeyProcessThread(void);
const TCHAR szevtUserInput[] = L"FriendlyARM/ButtonEvent";
DWORD UserKeyProcessThread(void)
{
DWORD IRQ;
// 创建一个事件
KeyEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
if (!KeyEvent)
{
RETAILMSG(1,(TEXT("ERROR:KEL:Failed to create event.\r\n")));
return FALSE;
}
// 将物理中断号转换为逻辑中断号
// IRQ 物理中断号;g_KeySysIntr逻辑中断号
IRQ = 36;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,&IRQ,sizeof(UINT32),&g_KeySysIntr[0],sizeof(UINT32),NULL))
{
RETAILMSG(1,(TEXT("ERROR:KEL: Failed to request sysintr value.\r\n")));
return FALSE;
}
IRQ = 39;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,&IRQ,sizeof(UINT32),&g_KeySysIntr[1],sizeof(UINT32),NULL))
{
RETAILMSG(1,(TEXT("ERROR:KEL: Failed to request sysintr value.\r\n")));
return FALSE;
}
IRQ = 41;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,&IRQ,sizeof(UINT32),&g_KeySysIntr[2],sizeof(UINT32),NULL))
{
RETAILMSG(1,(TEXT("ERROR:KEL: Failed to request sysintr value.\r\n")));
return FALSE;
}
IRQ = 42;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,&IRQ,sizeof(UINT32),&g_KeySysIntr[3],sizeof(UINT32),NULL))
{
RETAILMSG(1,(TEXT("ERROR:KEL: Failed to request sysintr value.\r\n")));
return FALSE;
}
// 通知系统使能这个中断(g_KeySysIntr),并且当这个中断产生时产生一个事件、
if (!InterruptInitialize(g_KeySysIntr[0],KeyEvent,NULL,0))
{
RETAILMSG(1,(TEXT("Fail to initialize key interrupt event\r\n")));
return FALSE;
}
if (!InterruptInitialize(g_KeySysIntr[1],KeyEvent,NULL,0))
{
RETAILMSG(1,(TEXT("Fail to initialize key interrupt event\r\n")));
return FALSE;
}
if (!InterruptInitialize(g_KeySysIntr[2],KeyEvent,NULL,0))
{
RETAILMSG(1,(TEXT("Fail to initialize key interrupt event\r\n")));
return FALSE;
}
if (!InterruptInitialize(g_KeySysIntr[3],KeyEvent,NULL,0))
{
RETAILMSG(1,(TEXT("Fail to initialize key interrupt event\r\n")));
return FALSE;
}
while(1)
{
// 等待中断发生
WaitForSingleObject(KeyEvent,INFINITE);
const char nIndex[] = { 0, 3, 5, 6};
const char nIndex2[]= { 5, 6, 7, 8};
// 扫描Kn(1..4)的状态并赋给LEDn(1..4)
for (int i=0;i<4;i++)
{
if (s2440IOP->rGPGDAT & (0x01 << nIndex))
{
s2440IOP->rGPBDAT = s2440IOP->rGPBDAT | (0x01 << nIndex2);
}
else
{
s2440IOP->rGPBDAT = s2440IOP->rGPBDAT &~ (0x01 << nIndex2);
}
}
// 已经完成中断的处理,重新开启该中断
// K1
if(s2440IOP->rEINTMASK & (DWORD)(0x1<<8))
{
InterruptDone(g_KeySysIntr[0]);
}
//EINT11 - K2
if(s2440IOP->rEINTMASK & (DWORD)(0x1<<11))
{
InterruptDone(g_KeySysIntr[1]);
}
//EINT13 - K3
if(s2440IOP->rEINTMASK & (DWORD)(0x1<<13))
{
InterruptDone(g_KeySysIntr[2]);
}
//EINT14 - K4
if(s2440IOP->rEINTMASK & (DWORD)(0x1<<14))
{
InterruptDone(g_KeySysIntr[3]);
}
}
}
void Virtual_Alloc()
{
s2440IOP = (volatile IOPreg *) VirtualAlloc(0,sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS);
// 申请虚拟内存空间
if(s2440IOP == NULL)
{
RETAILMSG(1,(TEXT("For s2440IOP: VirtualAlloc failed!\r\n")));
}
else
{
// 将虚拟内存空间映射到物理内存空间
if(!VirtualCopy((PVOID)s2440IOP,(PVOID)(IOP_BASE),sizeof(IOPreg),PAGE_READWRITE | PAGE_NOCACHE ))
{
RETAILMSG(1,(TEXT("For s2440IOP: VirtualCopy failed!\r\n")));
}
}
// 申请虚拟内存空间
s2440INT = (volatile INTreg *) VirtualAlloc(0,sizeof(INTreg),MEM_RESERVE, PAGE_NOACCESS);
if(s2440INT == NULL)
{
RETAILMSG(1,(TEXT("For s2440INT: VirtualAlloc failed!\r\n")));
}
else
{
// 将虚拟内存空间映射到物理内存空间
if(!VirtualCopy((PVOID)s2440INT,(PVOID)(INT_BASE),sizeof(INTreg),PAGE_READWRITE | PAGE_NOCACHE )) {
RETAILMSG(1,(TEXT("For s2440INT: VirtualCopy failed!\r\n")));
}
}
}
BOOL WINAPI
DllEntry(HANDLE hinstDLL,
DWORD dwReason,
LPVOID Reserved/* lpvReserved */)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
DEBUGREGISTER((HINSTANCE)hinstDLL);
return TRUE;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
#ifdef UNDER_CE
case DLL_PROCESS_EXITING:
break;
case DLL_SYSTEM_STARTED:
break;
#endif
}
return TRUE;
}
BOOL KEL_Deinit(DWORD hDeviceContext)
{
BOOL bRet = TRUE;
RETAILMSG(1,(TEXT("USERKEY: KEY_Deinit\r\n")));
// 关闭线程
CloseHandle(KeyThread);
// 释放内存空间
VirtualFree((void*)s2440IOP, sizeof(IOPreg), MEM_RELEASE);
VirtualFree((void*)s2440INT, sizeof(INTreg), MEM_RELEASE);
return TRUE;
}
BOOL KeyGpioInit()
{
RETAILMSG(1,(TEXT("Key_Gpio_Setting----\r\n")));
//s2440IOP->rGPGUP = 0xffff;
// K1设置为输入,上升沿或者下降沿都触发
s2440IOP->rGPGCON = (s2440IOP->rGPGCON & ~(0x3 << 0x0)) | (0x2 << 0x0); // GPG0 == EINT8
s2440IOP->rEXTINT1 = (s2440IOP->rEXTINT1 & ~(0x7<< 0)) | (0x6 << 0);
// K2设置为输入,上升沿或者下降沿都触发
s2440IOP->rGPGCON = (s2440IOP->rGPGCON & ~(0x3 << 6)) | (0x2 << 6); // GPG3 == EINT11
s2440IOP->rEXTINT1 = (s2440IOP->rEXTINT1 & ~(0x7<< 12)) | (0x6 << 12);
// K3设置为输入,上升沿或者下降沿都触发
s2440IOP->rGPGCON = (s2440IOP->rGPGCON & ~(0x3 << 10)) | (0x2 << 10); // GPG5 == EINT13
s2440IOP->rEXTINT1 = (s2440IOP->rEXTINT1 & ~(0x7<< 20)) | (0x2 << 20);
// K4设置为输入,上升沿或者下降沿都触发
s2440IOP->rGPGCON = (s2440IOP->rGPGCON & ~(0x3 << 12)) | (0x2 << 12); // GPG6 == EINT14
s2440IOP->rEXTINT1 = (s2440IOP->rEXTINT1 & ~(0x7<< 24)) | (0x4 << 24);
// LED1设置为输出
s2440IOP->rGPBCON = (s2440IOP->rGPBCON &~(3 << 10)) | (1<< 10); // GPB5 == OUTPUT.
// LED2设置为输出
s2440IOP->rGPBCON = (s2440IOP->rGPBCON &~(3 << 12)) | (1<< 12); // GPB6 == OUTPUT.
// LED3设置为输出
s2440IOP->rGPBCON = (s2440IOP->rGPBCON &~(3 << 14)) | (1<< 14); // GPB7 == OUTPUT.
// LED4设置为输出
s2440IOP->rGPBCON = (s2440IOP->rGPBCON &~(3 << 16)) | (1<< 16); // GPB8 == OUTPUT.
return TRUE;
}
DWORD KEL_Init(DWORD dwContext)
{
DWORD threadID; // thread ID
RETAILMSG(1,(TEXT("KEY_Init----\r\n")));
// 申请内存
Virtual_Alloc();
// 初始化寄存器
KeyGpioInit();
// 创建线程
KeyThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)UserKeyProcessThread, 0, 0, &threadID);
if (NULL == KeyThread )
{
RETAILMSG(1,(TEXT("ERROR: failed to Create Key Thread!\r\n")));
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
DWORD KEL_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode)
{
RETAILMSG(1,(TEXT("KEYLED: KEL_Open ret is\r\n")));
return TRUE;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
BOOL KEL_Close(DWORD hOpenContext)
{
RETAILMSG(1,(TEXT("KEYLED: KEL_Close ret is\r\n")));
return TRUE;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void KEL_PowerDown(DWORD hDeviceContext)
{
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void KEL_PowerUp(DWORD hDeviceContext)
{
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
DWORD KEL_Read(DWORD hOpenContext, LPVOID pBuffer, DWORD Count)
{
RETAILMSG(1,(TEXT("KEYLED: KEL_Read ret is\r\n")));
return 1;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
DWORD KEL_Seek(DWORD hOpenContext, long Amount, DWORD Type)
{
RETAILMSG(1,(TEXT("KEYLED: KEL_Seek ret is\r\n")));
return 0;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
DWORD KEL_Write(DWORD hOpenContext, LPCVOID pSourceBytes, DWORD NumberOfBytes)
{
RETAILMSG(1,(TEXT("KEYLED: KEL_Write ret is\r\n")));
return 0;
}
二、 把驱动程序添加到BSP中编译
1) 在mini2440\Src\Drivers下建立KeyLed目录,并在dirs文件中加入此目录,使系统编译bsp的时候可以编译这个文件
2) 为驱动创建Makefile文件
#
# 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 Peg
#
!INCLUDE $(_MAKEENVROOT)\makefile.def
3) 为驱动创建source文件
!if 0
File: sources
Author: fire
Copyright (c) 1995-2002 Microsoft Corporation. All rights reserved.
!endif
RELEASETYPE=PLATFORM
TARGETNAME=KEYLED
TARGETTYPE=DYNLINK
DLLENTRY=DllEntry
TARGETLIBS= \
$(_COMMONSDKROOT)\lib\$(_CPUINDPATH)\coredll.lib \
MSC_WARNING_LEVEL = $(MSC_WARNING_LEVEL) /W3 /WX
INCLUDES= \
$(_TARGETPLATROOT)\inc; \
$(_COMMONOAKROOT)\inc; \
$(_PUBLICROOT)\common\oak\inc;$(_PUBLICROOT)\common\sdk\inc;$(_PUBLICROOT)\common\ddk\inc; \
..\..\inc
SOURCES= \
KeyLed.cpp \
4) 编写Keyled.def导出dll符号
;
; Windows CE Key Driver. Written by flyingfingers
LIBRARY KeyLed
EXPORTS
KEL_Close
KEL_Deinit
KEL_Init
; KEL_IOControl
KEL_Open
KEL_PowerDown
KEL_PowerUp
KEL_Read
KEL_Seek
KEL_Write
5) 把驱动加入内核
在配置文件platform.bib中加入以下内容:(不是很明白为什么要加入IF BSP_NOKEL)
IF BSP_NOKEL !
keyled.dll $(_FLATRELEASEDIR)\keyled.dll NK SH
ENDIF BSP_NOKEL !
6) 把驱动加入注册表
在注册表文件platform.reg中加入以下内容:
IF BSP_NOKEL !
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\keyled]
"Prefix"="KEL"
"Dll"="keyled.dll"
"Order"="200"
ENDIF BSP_NOKEL !
三、 上机结果
友善之臂的Micro2440+WINCE5.0
按下Kn,LEDn亮;松开Kn,LEDn灭(n=1..4)
中断处理。
四、 中断线程我现在采用的方法
线程函数
{
创建一个事件。
设置优先级
将物理中断号转换为逻辑中断号
通知系统使能这个中断,并且当这个中断产生时产生一个事件
等待中断发生
中断处理
中断完成
}
初学WINCE。欢迎交流。