转自:http://haiou-arm.blog.sohu.com/rss 感谢博主
开发平台:蓝海微芯的s3c2440A开发板;
开发环境:PB5.0;
具体过程如下:
1、编写代码:
在PB环境下:File->New Project or File新建一个Project名为:KeyIntr,路径就放在我要编译的BSP下的Drivers里,路径如下图,另外驱动和硬件直接相关,按键驱动电路如下:
/***********************************************************************************************************
**-------------------------------------------------------------------------------------------------------
**按键中断涉及EINT0和EINT2,修改相应文件如下:
**1、D:\WINCE500\PLATFORM\smdk2440\INC\oalintr.h
** #define SYSINTR_KEYINT (SYSINTR_FIRMWARE+13)
//chagned from SYSINTR_POWER to SYSINTR_KEYINT by haiou in 081215
**-------------------------------------------------------------------------------------------------------
**2、D:\WINCE500\PLATFORM\smdk2440\KERNEL\HAL\cfw.c
** (1)OEMInterruptEnable中:
** s2440INT->rSRCPND = s2440INT->rSRCPND;
** s2440INT->rSRCPND = BIT_EINT0 | BIT_EINT2; //add the "|" by haiou in 081225
**
** s2440INT->rINTPND = s2440INT->rINTPND;
** //if ((s2440INT->rINTPND & BIT_EINT0) | (s2440INT->rINTPND & BIT_EINT2)) //delete by haiou in 081225
** s2440INT->rINTPND = BIT_EINT0 | BIT_EINT2;//add the "|" by haiou in 081225
**
** // S3C2440X Developer Notice (page 4) warns against writing a 1 to a 0 bit in the INTPND register.
** //if (s2440INT->rINTPND & BIT_EINT0) //delete by haiou in 081225
** // s2440INT->rINTPND |= BIT_EINT0;//add the "|" by haiou in 081225
** //s2440INT->rINTMSK &= ~BIT_EINT0;
** // S3C2440X Developer Notice (page 4) warns against writing a 1 to a 0 bit in the INTPND register.
** //if (s2440INT->rINTPND & BIT_EINT2) //delete by haiou in 081225
** // s2440INT->rINTPND |= BIT_EINT2;//add the "|" by haiou in 081225
** s2440INT->rINTMSK &= ~(BIT_EINT0 | BIT_EINT2);
** RETAILMSG(1,(TEXT("::: SYSINTR_KEYINT OEMInterruptEnable\r\n")));
** break;
** (2)OEMInterruptDisable中:
** case SYSINTR_KEYINT: //chagned from SYSINTR_POWER to SYSINTR_KEYINT by haiou in 081215
** s2440INT->rINTMSK |= BIT_EINT0;
** s2440INT->rINTMSK |= BIT_EINT2;
** break;
** (3)OEMInterruptDone中:
** case SYSINTR_KEYINT: //chagned from SYSINTR_POWER to SYSINTR_KEYINT by haiou in 081215
** s2440INT->rSRCPND = s2440INT->rSRCPND;
** s2440INT->rSRCPND = BIT_EINT0 | BIT_EINT2; //add the "|" by haiou in 081225
** s2440INT->rINTPND = s2440INT->rINTPND;
** //if ((s2440INT->rINTPND & BIT_EINT0) | (s2440INT->rINTPND & BIT_EINT2)) //delete by haiou in 081225
** s2440INT->rINTPND = BIT_EINT0 | BIT_EINT2;//add the "|" by haiou in 081225
**
** //s2440INT->rSRCPND = BIT_EINT0;//delete by haiou in 081225
** // S3C2440X Developer Notice (page 4) warns against writing a 1 to a 0 bit in the INTPND register.
** //if (s2440INT->rINTPND & BIT_EINT0) s2440INT->rINTPND = BIT_EINT0;//delete by haiou in 081225
** s2440INT->rINTMSK &= ~BIT_EINT0;
** //s2440INT->rSRCPND = BIT_EINT2;//delete by haiou in 081225
** // S3C2440X Developer Notice (page 4) warns against writing a 1 to a 0 bit in the INTPND register.
** //if (s2440INT->rINTPND & BIT_EINT2) s2440INT->rINTPND = BIT_EINT2;//delete by haiou in 081225
** s2440INT->rINTMSK &= ~BIT_EINT2;
** RETAILMSG(1,(TEXT("::: SYSINTR_KEYINT OEMInterruptDone\r\n")));
** break;
**------------------------------------------------------------------------------------------------------------------------
**3、D:\WINCE500\PLATFORM\smdk2440\KERNEL\HAL\ARM\armint.c的OEMInterruptHandler()函数
** (1)
** else if (IntPendVal == INTSRC_EINT2) // EINT2
** {
** s2440INT->rINTMSK |= BIT_EINT2;
** s2440INT->rSRCPND = BIT_EINT2; //Interrupt Clear
** if (s2440INT->rINTPND & BIT_EINT2) s2440INT->rINTPND = BIT_EINT2;
** return(SYSINTR_KEYINT); //chagned from SYSINTR_POWER to SYSINTR_KEYINT by haiou in 081215
** }
** (2)
** else if (IntPendVal == INTSRC_EINT0) // POWER BUTTON
** {
** s2440INT->rINTMSK |= BIT_EINT0;
** s2440INT->rSRCPND = BIT_EINT0; // Interrupt Clear
** if (s2440INT->rINTPND & BIT_EINT0) s2440INT->rINTPND = BIT_EINT0;
** return(SYSINTR_KEYINT); //chagned from SYSINTR_POWER to SYSINTR_KEYINT by haiou in 081215
** }
**--------------------------------------------------------------------------------------------------------------------------
*****************************************************************************************************************************/
/*******************************************************************************************************
**--------------File Info-------------------------------------------------------------------------------
** File Name: KeyIntr.c
** Last modified Date: 2008-12-14
** Description: This driver uses EINT0\EINT2\GPB6\GPB7 button(KEY1\KEY2\KEY3\KEY4) On s3c2440 made by bluemcu
** Created By: haiou 罗恒欧
** Version: V1.0
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
#include <windows.h>
#include <tchar.h>
#include <nkintr.h>
#include <types.h>
#include "oalintr.h"
#include <pm.h> //??????haiou
#include "pmplatform.h" //??????haiou
#include "drv_glob.h" //??????haiou
//#include "2440addr.h" //
#include "s2440.h"
HANDLE g_KeyIntr;//中断事件句柄
HANDLE g_KeyIntrThread;//中断线程句柄
UINT32 g_KillKeyInterIST = FALSE; //中断服务线程(IST)
volatile IOPreg *v_pIOPregs; //定义IOPreg结构的指针,以便对IO口进行初始化设置
//volatile PWMreg *v_pWMPregs;
//volatile INTreg *v_s2440INT = (INTreg *)INT_BASE;
BYTE g_KeyNumber = 0xFF; //按键编号
UINT32 gOpenCount = 0; //驱动打开计数
CRITICAL_SECTION cs;//临界区
void Delay(int time)
{
/* unsigned int PCLK = 400000000;
unsigned int val = (PCLK>>3)/1000-1;
(v_pWMPregs->rTCFG0) &= ~(0xff<<8);
(v_pWMPregs->rTCFG0) |= 3<<8; //prescaler = 3+1
(v_pWMPregs->rTCFG1) &= ~(0xf<<12);
(v_pWMPregs->rTCFG1) |= 0<<12; //mux = 1/2
(v_pWMPregs->rTCNTB3) = val;
(v_pWMPregs->rTCMPB3) = val>>1; // 50%
(v_pWMPregs->rTCON) &= ~(0xf<<16);
(v_pWMPregs->rTCON) |= 0xb<<16; //interval, inv-off, update TCNTB3&TCMPB3, start timer 3
(v_pWMPregs->rTCON) &= ~(2<<16); //clear manual update bit
while(time--)
{
while((v_pWMPregs->rTCNTO3)>=val>>1);
while((v_pWMPregs->rTCNTO3)<val>>1);
};
*/
// time=0: adjust the Delay function by WatchDog timer.
// time>0: the number of loop time
// resolution of time is 100us.
int i;
for(i=0;i<1000;i++);
}
/*******************************************************************************************
函数名称: Port_Init
描 述: 配置外部中断引脚并使能为 下降 沿触发,配置GPB6和GPB7输出低电平
输入参数: 无
输出参数: 无
返 回: 无
********************************************************************************************/
void Port_Init(void)
{
//**** PORT B GROUP
//Ports : GPB10 GPB9 GPB8 GPB7 GPB6 GPB5 GPB4 GPB3 GPB2 GPB1 GPB0
//Signal : nXDREQ0 nXDACK0 nXDREQ1 nXDACK1 nSS_KBD nDIS_OFF L3CLOCK L3DATA L3MODE nIrDATXDEN Keyboard
//Setting: INPUT OUTPUT INPUT OUTPUT INPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT
//Binary : 00 , 01 00 , 01 00 , 01 01 , 01 01 , 01 01
v_pIOPregs->rGPBCON &= ~((3<<12)|(3<<14));
v_pIOPregs->rGPBCON |= ((1<<12)|(1<<14)); //从新设置为输出
v_pIOPregs->rGPBUP |= (3<<6); //禁止其上拉
v_pIOPregs->rGPBDAT &= ~(3<<6); //输出为低电平
//*** PORT F GROUP
//Ports : GPF7 GPF6 GPF5 GPF4 GPF3 GPF2 GPF1 GPF0
//Signal : nLED_8 nLED_4 nLED_2 nLED_1 nIRQ_PCMCIA EINT2 KBDINT EINT0
//Setting: Output Output Output Output EINT3 EINT2 EINT1 EINT0
//Binary : 01 01 , 01 01 , 10 10 , 10 10
v_pIOPregs->rGPFUP &= (~((3<<2)|(3<<0))) | ((1<<2)|(1<<0)) ; // The pull up function is disabled GPF[2:0]
v_pIOPregs->rGPFCON &= (~((3<<4)|(3<<0))) | ((2<<4)|(2<<0)) ; //GPF2,0 set EINT
v_pIOPregs->rEXTINT0 &= ~(7|(7<<8));
v_pIOPregs->rEXTINT0 |= (2|(2<<8)); //set eint0,2 falling edge triggered
}
/*******************************************************************************************
函数名称: EINT_InitializeAddresses
描 述: 取得相关寄存器的虚拟地址
输入参数: 无
输出参数: 无
返 回: > 0 分配得到的虚拟地址; FALSE: 分配失败
*******************************************************************************************/
BOOL EINT_InitializeAddresses(VOID)
{
BOOL RetValue = TRUE;
RETAILMSG(1, (TEXT(">>> EINT_initalization address..set..\r\n")));
/* IO Register Allocation */
v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS);
if (v_pIOPregs == NULL)
{
ERRORMSG(1,(TEXT("For IOPregs : VirtualAlloc failed!\r\n")));
RetValue = FALSE;
}
else
{
//在s2440.h中:#deifine IOP_BASE 0xB1600000,而实际物理地址是:0x56000000;
if (!VirtualCopy((PVOID)v_pIOPregs, (PVOID)((IOP_BASE-0x5B600000)>>8), sizeof(IOPreg), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
{
ERRORMSG(1,(TEXT("For IOPregs: VirtualCopy failed!\r\n")));
RetValue = FALSE;
}
}
if (!RetValue)
{
RETAILMSG (1, (TEXT("::: EINT_InitializeAddresses - Fail!!\r\n") ));
if (v_pIOPregs)
{
VirtualFree((PVOID)v_pIOPregs, 0, MEM_RELEASE);
}
v_pIOPregs = NULL;
}
else
RETAILMSG (1, (TEXT("::: EINT_InitializeAddresses - Success\r\n") ));
RETAILMSG(1, (TEXT("*v_pIOPregs = 0x%x===========virtual address test by haiou\r\n"), *v_pIOPregs));
return(RetValue);
}
/*******************************************************************************************
函数名称: Key_IsPushed
描 述: 查询按键是否已按下
输入参数: 无
输出参数: 无
返 回: FALSE: 按键未按下 TRUE: 按键已按下
*******************************************************************************************/
BOOL Key_IsPushed(void)
{
if ((((v_pIOPregs->rGPFDAT)&(1<<0)) == 0) | (((v_pIOPregs->rGPFDAT)&(1<<2)) == 0))
return TRUE;
else
return FALSE;
//return (((v_pIOPregs->rGPFDAT & (1 << 0)) | ((v_pIOPregs->rGPFDAT & (1 << 2))) ? FALSE : TRUE);
}
/*******************************************************************************************
函数名称: KeyScan
描 述: 获得相应按键标识
输入参数: 无
输出参数: 按键标识
返 回: 0xff 无按键按下
1 Key1按下
2 Key2按下
3 Key3按下
4 Key4按下
*******************************************************************************************/
BYTE KeyScan(void)
{
//RETAILMSG(1, (TEXT("v_pIOPregs->rGPFDAT = 0x%x===========test by haiou\r\n"), v_pIOPregs->rGPFDAT));
(v_pIOPregs->rGPBDAT) &= ~(1<<6); //GPB6输出0
(v_pIOPregs->rGPBDAT) |= 1<<7; //GPB7输出1
//RETAILMSG(1, (TEXT("k1 or k3, v_pIOPregs->rGPFDAT = 0x%x===========test by haiou\r\n"), v_pIOPregs->rGPFDAT));
if(((v_pIOPregs->rGPFDAT)&(1<<0)) == 0)
{
RETAILMSG(1, (TEXT("K1 has been pressed!\r\n")));
return 1;
}
else if(((v_pIOPregs->rGPFDAT)&(1<<2)) == 0)
{
RETAILMSG(1, (TEXT("K3 has been pressed!\r\n")));
return 3;
}
(v_pIOPregs->rGPBDAT) &= ~(1<<7); //GPB7输出0
(v_pIOPregs->rGPBDAT) |= 1<<6; //GPB6输出1
//RETAILMSG(1, (TEXT("k2 or k4, v_pIOPregs->rGPBDAT = 0x%x===========test by haiou\r\n"), v_pIOPregs->rGPBDAT));
if(((v_pIOPregs->rGPFDAT)&(1<<0)) == 0)
{
RETAILMSG(1, (TEXT("K2 has been pressed!\r\n")));
return 2;
}
else if(((v_pIOPregs->rGPFDAT)&(1<<2)) == 0)
{
RETAILMSG(1, (TEXT("K4 has been pressed!\r\n")));
return 4;
}
else
{
RETAILMSG(1, (TEXT("Wrong Key been pressed!\r\n")));
return 0xFF;
}
}
/*******************************************************************************************
函数名称: KeyIntr_Thread
描 述: 外部中断按键服务线程IST,将按键标识敷给全局变量g_KeyNumber
输入参数: PVOID pArg: 线程输入参数
输出参数: 无
返 回: 1 或 0
*******************************************************************************************/
DWORD KeyIntr_Thread(PVOID pArg)
{
DWORD ret;
g_KeyIntr = CreateEvent(NULL, FALSE, FALSE, NULL);
if(g_KeyIntr == NULL)
{
RETAILMSG(1, (TEXT("DEMO:Event creation failed!\r\n")));
return 0;
}
if(!(InterruptInitialize(SYSINTR_KEYINT,g_KeyIntr,0,0)))
{
RETAILMSG(1,(TEXT("DEMO:InterruptInitialize failed\r\n")));
CloseHandle(g_KeyIntr);
return 0;
}
while (1)
{
ret = WaitForSingleObject(g_KeyIntr, INFINITE);
if ((ret == WAIT_OBJECT_0) && (g_KillKeyInterIST == FALSE))
{
//InterruptDisable(SYSINTR_KEYINT);//进中断后在未处理完中断IST前先关掉中断;
InitializeCriticalSection(&cs);//初始化临界区
EnterCriticalSection(&cs);//进入临界区
//进入中断后将I/O口由中断功能转化为输入
//v_pIOPregs->rGPFCON &= (~((3<<4)|(3<<0))) | ((00<<4)|(00<<0)) ; //GPF2,0 set I/O input
//if ((v_s2440INT->rINTPND & BIT_EINT0) | (v_s2440INT->rINTPND & BIT_EINT2))
//{
// v_s2440INT->rINTPND = BIT_EINT0 | BIT_EINT2;
// v_s2440INT->rSRCPND = BIT_EINT0 | BIT_EINT2;
//}
//RETAILMSG(1, (TEXT("Is Key Pushed really?\r\n")));
//RETAILMSG(1, (TEXT("v_pIOPregs->rGPFDAT = 0x%x===========test by haiou\r\n"), v_pIOPregs->rGPFDAT));
if (Key_IsPushed())
{
Delay(200); /* 延时用于滤去噪声 */
if (Key_IsPushed()) /* 外部中断按键确实已按下 */
{
RETAILMSG(1, (TEXT("v_pIOPregs->rGPFDAT = 0x%x===========test by haiou\r\n"), v_pIOPregs->rGPFDAT));
g_KeyNumber = KeyScan();
//RETAILMSG(1, (TEXT("Interrupt occur,Key has been pressed!\r\n")));
v_pIOPregs->rGPBDAT &= ~(3<<6); //扫描结束,GPB6\GPB7从新输出为低电平
//v_pIOPregs->rGPFCON &= (~((3<<4)|(3<<0))) | ((2<<4)|(2<<0)) ; //GPF2,0 set EINT
}
}
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);//删除临界区
}
else
{
CloseHandle(g_KeyIntr);
RETAILMSG(1, (TEXT("::: EINTKey_IntrThread Exit. \r\n")));
return 0;
} //if (ret != WAIT_OBJECT_0) or Error occurs
InterruptDone(SYSINTR_KEYINT); /* 通知内核: 中断处理结束 */
}
return 1;
}
/*******************************************************************************************
函数名称: SetInterrupt
描 述: 创建中断IST,并设置中断优先级
输入参数: 无
输出参数: 无
返 回: > 0 分配得到的虚拟地址; FALSE: 分配失败
*******************************************************************************************/
void SetInterrupt(void)
{
DWORD IDThread;
int m_KeyIntrPriority;
g_KeyIntrThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)KeyIntr_Thread, 0, 0, &IDThread);
if(g_KeyIntrThread==NULL)
{
RETAILMSG(1,(TEXT("DEMO:Thread creation failed!\r\n")));
return; //如果执行了这句,该函数后面的语句将不再执行
}
m_KeyIntrPriority = 5;
if(!CeSetThreadPriority(g_KeyIntrThread, m_KeyIntrPriority))
{
RETAILMSG(1,(TEXT("DEMO:Failed setting Thread Priority!\r\n")));
return;
}
}
/*******************************************************************************************
函数名称: KEY_Init
描 述: 驱动程序初始化函数
输入参数: DWORD dwContext: 设备管理器传递给本驱动的参数, 通常为流接口驱动在注册表内的位置
输出参数: 无
返 回: 驱动程序句柄
*******************************************************************************************/
DWORD KEY_Init(DWORD dwContext)
{
// 取得 GPIO 相关寄存器的虚拟地址空间
if (EINT_InitializeAddresses() == FALSE)
{
return 0;
}
Port_Init();
g_KeyNumber = 0xff;
SetInterrupt();
RETAILMSG(1, (TEXT("::: KEY_Init Sucessfully! \r\n")));
return (DWORD)g_KeyIntrThread;
}
/*******************************************************************************************
函数名称: KEY_Close
描 述: 驱动程序关闭函数
输入参数: DWORD Handle:驱动程序句柄
输出参数: 无
返 回: FALSE: 失败 TRUE: 成功
*******************************************************************************************/
BOOL KEY_Close(DWORD Handle)
{
g_KeyNumber = 0xff;
if (gOpenCount > 0)
gOpenCount = 0;
return TRUE;
}
/*******************************************************************************************
函数名称: KEY_Deinit
描 述: 驱动程序卸载函数
输入参数: DWORD dwContext: 驱动程序句柄
输出参数: 无
返 回: FALSE: 失败 TRUE: 成功
*******************************************************************************************/
BOOL KEY_Deinit(DWORD dwContext)
{
g_KillKeyInterIST = TRUE;
Sleep(200); /* 等待中断服务线程退出 */
InterruptDone(SYSINTR_KEYINT);
InterruptDisable(SYSINTR_KEYINT);
if (v_pIOPregs)
{
VirtualFree((PVOID) v_pIOPregs, 0, MEM_RELEASE);
}
gOpenCount = 0;
g_KeyNumber = 0xff;
return TRUE;
}
/*******************************************************************************************
函数名称: KEY_Open
描 述: 打开驱动程序
输入参数: DWORD dwData : 驱动程序引用事例句柄
DWORD dwAccess : 访问请求代码,是读和写的组合
DWORD dwShareMode: 共享模式
输出参数: 无
返 回: 驱动程序引用事例句柄
*******************************************************************************************/
DWORD KEY_Open(DWORD dwData, DWORD dwAccess, DWORD dwShareMode)
{
if (gOpenCount > 0)
{
return 0; // 本驱动只允许单一访问
}
gOpenCount = 1;
return gOpenCount;
}
/*******************************************************************************************
函数名称: KEY_Read
描 述: 读取按键标识
输入参数: DWORD Handle : 驱动程序引用事例句柄
LPVOID pBuffer : 接收缓冲区
DWORD dwNumBytes: 要读的字节数
输出参数: 无
返 回: 实际读到字节数
*******************************************************************************************/
DWORD KEY_Read(DWORD Handle, LPVOID pBuffer, DWORD dwNumBytes)
{
uchar* pReadBuffer;
if ((pBuffer == NULL) || (dwNumBytes <= 0))
{
return 0;
}
/*驱动程序和应用程序之间传递数据时何时调用MapPtrToProcess?
因为设备管理器负责加载驱动程序DLL,这意味着当应用程序调用驱动程序接口函数的时候,WINCE内核会将调
用驱动程序接口函数的线程转移到设备管理器的进程空间然后执行具体的驱动程序代码,应用程序和设备管理
器处于两个进程空间,这就造成设备管理器无法访问应用程序传递的指针(虚拟地址),所以当我们在应用程
序中传递指针给流驱动程序接口函数时,WINCE内核从中作了一个地址映射,例如ReadFile、WriteFile、
DeviceIoControl函数的参数凡是指针都经过了映射才传递给驱动程序,所以很多驱动程序开发者并不了解其中
的奥秘就可以编程了。但是如果参数是一个指向一个结构体的指针,而结构体里包括一个或多个指针,那么WINCE
内核并不负责映射,所以就需要开发者在驱动程序接口函数中调用API函数MapPtrToProcess来映射地址。例如:
pPointer_retval = MapPtrToProcess(pPointer, GetCallerProcess()); */
pReadBuffer = (uchar*)MapPtrToProcess(pBuffer, GetCallerProcess()); //pReadBuffer是应用程序的pBuffer在设备管理器上的地址映射!
*pReadBuffer = g_KeyNumber; //是否需要进行强制转换haiou
//*pReadBuffer表示地址里存的内容
return 1;
}
/*******************************************************************************************
函数名称: KEY_IOControl
描 述: 驱动程序 I/O 请求
输入参数:
输出参数:
返 回: 本驱动不支持该请求,返回 FALSE
*******************************************************************************************/
BOOL KEY_IOControl(DWORD Handle, DWORD dwIoControlCode, PBYTE pInBuf,
DWORD nInBufSize, PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)
{
return FALSE;
}
/*******************************************************************************************
函数名称: KEY_Write
描 述: 写函数,本驱动不支持
输入参数:
输出参数:
返 回:
*******************************************************************************************/
DWORD KEY_Write(DWORD Handle, LPCVOID pBuffer, DWORD dwNumBytes)
{
return 0;
}
/*******************************************************************************************
函数名称: KEY_Seek
描 述: 对设备的数据指针进行操作,本驱动不支持该函数
输入参数:
输出参数:
返 回:
*******************************************************************************************/
DWORD KEY_Seek(DWORD Handle, long lDistance, DWORD dwMoveMethod)
{
return 0;
}
/*******************************************************************************************
函数名称: KEY_PowerUp
描 述: 电源上电驱动处理函数
输入参数:
输出参数:
返 回: 无
*******************************************************************************************/
void KEY_PowerUp(void)
{
return;
}
/*******************************************************************************************
函数名称: KEY_PowerDown
描 述: 电源下电驱动处理函数
输入参数:
输出参数:
返 回: 无
*******************************************************************************************/
void KEY_PowerDown(void)
{
return;
}
/*******************************************************************************************
函数名称: DllMain
描 述: 驱动程序动态库入口
输入参数:
输出参数:
返 回:
*******************************************************************************************/
BOOL WINAPI DllMain(HANDLE hinstDll, DWORD dwReason, LPVOID lpReserved)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
RETAILMSG(1, (TEXT("KEY_DllMain: DLL_PROCESS_ATTACH\r\n")));
break;
case DLL_PROCESS_DETACH:
RETAILMSG(1, (TEXT("KEY_DllMain: DLL_PROCESS_DETACH\r\n")));
break;
}
return TRUE;
}
2、修改def文件,和KeyIntr.cpp在同一个目录下,名称为:KeyIntr.def:
; Copyright (c) 1999-2000 Microsoft Corporation. All rights reserved.
// by shin..
LIBRARY ser2440
EXPORTS
KEY_Init
KEY_Deinit
KEY_Open
KEY_Close
KEY_Read
KEY_Write
KEY_Seek
KEY_PowerDown
KEY_PowerUp
KEY_IOControl
3、修改makefile文件,和KeyIntr.def在同一个目录下:
# Copyright (c) 1999-2000 Microsoft Corporation. All rights reserved.
#
# 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
#
!INCLUDE $(_MAKEENVROOT)\makefile.def
4、修改sources文件,和makefile文件在同一个目录下:
!if 0
File: sources
Author: lmorri
Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
!endif
!ifdef ODO_NOSERIAL
SKIPBUILD=1
!endif
TARGETNAME=KeyIntr
RELEASETYPE=PLATFORM
TARGETTYPE=DYNLINK
DLLENTRY=DllMain
PREPROCESSDEFFILE=1
INCLUDES=\
$(_PUBLICROOT)\common\oak\inc;$(_PUBLICROOT)\common\sdk\inc;$(_PUBLICROOT)\common\ddk\inc; \
$(_TARGETPLATROOT)\inc
TARGETLIBS= \
$(_PROJECTROOT)\cesysgen\sdk\lib\$(_CPUINDPATH)\coredll.lib \
$(_PROJECTROOT)\cesysgen\oak\lib\$(_CPUINDPATH)\ceddk.lib \
DEFFILE=KeyIntr.def
SOURCES= \
KeyIntr.cpp \
5、修改platform.reg(注册表)文件,目录在D:\WINCE500\PLATFORM\smdk2440\FILES下,添加如下代码:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\KeyIntr]
"Prefix"="KEY"
"Dll"="KeyIntr.dll"
"Order"=dword:0
"Index"=dword:1
6、修改platform.bib文件(把DLL文件集成到NK中),添加代码如下:
KeyIntr.dll $(_FLATRELEASEDIR)\KeyIntr.dll NK SH
7、修改smdk2440.cec文件(只适合PB5.0),添加代码如下:
ComponentType
(
Name ( "Key Interrupt Driver" )
GUID ( {D6B8B642-25B6-48CE-ACE0-D57AC936E593} )
Description ( "The key on the demo of bluemcu" )
Group ( "\Device Drivers" )
Vendor ( "haiou" )
MaxResolvedImpsAllowed( 1 )
Implementations
(
Implementation
(
Name ( "KeyIntr" )
GUID ( {7CBB7423-7BAC-428D-B1F5-FA2B04EB6F35} )
Description ( "EINT0 EINT2 GPB6 GPB7" )
BSPPlatformDir ( "smdk2440" )
Version ( "5.0.0.0" )
Locale ( 0409 )
Vendor ( "haiou" )
Date ( "2008-12-21" )
SizeIsCPUDependent( 1 )
BuildMethods
(
BuildMethod
(
GUID ( {6B1CF3DC-13EE-4699-B4E9-AE04E23CCC7A} )
Step ( BSP )
CPU ( "ARMV4I" )
Action ( '#SRCCODE( SOURCES, "$(_WINCEROOT)\PLATFORM\smdk2440\DRIVERS\KeyIntr", "KeyIntr" )' )
)
)
)
)
)
该段代码的添加由CEC Editor自动完成,只要按照其格式填写即可,如下图:
至此,关于驱动的编写工作已全部完成,调试是通过串口打印的方式进行,在蓝海微芯的开发板上成功加载运行,并结合EVC编写的测试程序成功调用。
总结体会:
1、物理地址和虚拟地址的映射,如果映射不正确,往寄存器写数据和读寄存器里的值都不是实际物理地址的值,因为这个问题,浪费了我整整一星期的时间!~
2、买开发板一定要买大公司厂家的,技术支持强的,不然会出现类试,开发板上没有的硬件在BSP里有驱动,有的硬件有时候没有驱动,这样的结果就是BSP里文件混乱,对以后开发造成极大麻烦,比如在这个driver里要修改某个IO口状态,得把所有的驱动检查一遍,有可能在别的驱动力就已经对这个IO进行了操作。
到此,这块开发板的硬件驱动已全部具备,要开发编写应用程序了,哈哈~咱们以后继续讨论。
在此,感谢叶帆那片文章的帮助,链接为:http://www.winbile.net/cms/News/Newsc8c73i9243.aspx