写一个具体的按键驱动(WinCE5.0 S3C2440)

时间:2023-01-11 17:49:25

转自:http://haiou-arm.blog.sohu.com/rss 感谢博主

开发平台:蓝海微芯的s3c2440A开发板;
开发环境:PB5.0;

具体过程如下:
1、编写代码:
    在PB环境下:File->New Project or File新建一个Project名为:KeyIntr,路径就放在我要编译的BSP下的Drivers里,路径如下图,另外驱动和硬件直接相关,按键驱动电路如下:
写一个具体的按键驱动(WinCE5.0 S3C2440)写一个具体的按键驱动(WinCE5.0 S3C2440)

/***********************************************************************************************************
**-------------------------------------------------------------------------------------------------------
**按键中断涉及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自动完成,只要按照其格式填写即可,如下图:写一个具体的按键驱动(WinCE5.0 S3C2440)

    至此,关于驱动的编写工作已全部完成,调试是通过串口打印的方式进行,在蓝海微芯的开发板上成功加载运行,并结合EVC编写的测试程序成功调用。

    总结体会:
    1、物理地址和虚拟地址的映射,如果映射不正确,往寄存器写数据和读寄存器里的值都不是实际物理地址的值,因为这个问题,浪费了我整整一星期的时间!~
    2、买开发板一定要买大公司厂家的,技术支持强的,不然会出现类试,开发板上没有的硬件在BSP里有驱动,有的硬件有时候没有驱动,这样的结果就是BSP里文件混乱,对以后开发造成极大麻烦,比如在这个driver里要修改某个IO口状态,得把所有的驱动检查一遍,有可能在别的驱动力就已经对这个IO进行了操作。
    到此,这块开发板的硬件驱动已全部具备,要开发编写应用程序了,哈哈~咱们以后继续讨论。

    在此,感谢叶帆那片文章的帮助,链接为:http://www.winbile.net/cms/News/Newsc8c73i9243.aspx

Cannont locate precompiled header file

by:怀念放羊的日子

“BUILD:[00:0000000008:ERROR]Cannont locate precompiled header file:£” 是什么问题?在PB下编译自己写的驱动程序时出现的,在PB  下如何调试驱动程序?
 

解决过程:
 1、在QQ群里有人建议:Build OS->Clean Before Building,按照这个方法,sysgen后ERROR没有解决;
 2、这个问题的关键在于头文件没有被locate,在KeyIntr.cpp中将头文件删山间减修改了很多次,问题依旧;
 3、突然想到链接的概念,没有链接上?打开我的驱动文件,打开BSP某个驱动文件,开始对照,问题出在sources文件里;
 4、主要修改soures文件里的INCLUDES=\………,让其路径能找到.cpp中包含的头文件;
 5、一下子错误问题变成了3,这在情理之中——原来找不到头文件问题只报找不到头文件一个错误,现在头文件对了,这时候的错误才是真正驱动代码的错误,哈哈。

总结:驱动程序的soures文件,指定了驱动各文件的soures,.cpp中所包含的头文件须在INCLUDES中指明路径。

CabWiz.exe的使用

by:怀念放羊的日子

XP环境下安装文件以.msi的格式存在,然后点击安装;EVC下呢?

1、CE下以.cab的格式存在,那么怎样将EVC的.exe文件转换成.cab文件呢?简单说明操作如下:

2、将我生成后的EVC下文件“TcpClient.exe”复制到C盘根目录下;

3、编写.inf文件:新建文本文档,将后缀改为.inf,双击打开,编写如下代码:

   [Version]                
   Signature = "$Windows NT$"
   Provider = "haiou"
   CESignature = "$Windows CE$"
 
   [CEStrings]
   AppName = "TcpClient"
   InstallDir = %CE1%\%AppName%

   [SourceDisksNames]                
   1 = ,"Common files",,"C:\"

   [SourceDisksFiles]
   TcpClient.exe = 1

   [DefaultInstall]
   CopyFiles = CopyToProgramFiles
   AddReg = RegData

   [DestinationDirs]   
   CopyToProgramFiles = 0, %InstallDir%

   [CopyToProgramFiles]
   "TcpClient.exe",TcpClient.exe 

   [RegData]
   HKCU,Sofeware\%AppName%, MajorVersion, 0x00010001, 1
   HKCU,Sofeware\%AppName%, MajorVersion, 0x00010001, 0

同样将改.inf文件放在C盘根目录下;

4、将H:\program Files\Windows CE Platform Builder\5.0\CEPB下的BIN文件夹拷贝到C盘根目录下
   (BIN下包含CabWiz.exe工具和其相关的链接文件,当然也有其他工具文件)

5、XP下打开命令提示符操作:1、cd \
                          2、C:\>cd bin
                          3、C:\>cabwiz.exe "c:\tcpclient.inf"/dest "d:\"/err myfile.err
                          4、回车执行

6、查看D盘根目录,TcpClient.CAB文件已生成,拷贝到CE下点击直接安装;

7、gameover!


 

LINK : fatal error LNK1123

by:怀念放羊的日子

前天开始往系统里加载SQL 2000 for CE,安装过程提示无SDK,郁闷中……明明有,因为EVC一直和目标板(s3c2440)通信正常。

解决啊:1、将SDK卸载重装,卸载后EVC也不能运行了,应该将EVC也卸载重装。
       2、先装SDK,再装EVC,顺便装了自带的标准的SDK.
       3、安装SQL 2000 for CE 还是提示无SDK,郁闷中……试试EVC吧:可谓一波未平一波又起啊:
        EVC提示:1、fatal error CVT1102
                 2、LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt
       第一个问题好办:把common/evc/bin下的cvtres.exe拷到evc/wince500/bin下代替——解决!

    一、第二个问题是看了很多网站,说什么的都有:资源冲突、数据无效、病毒、ID资源……因为刚从硬件转过来,很多概念不明白,最多的是在resorse文件里折腾了很久,修改ID,删除ID……无济于事。

    二、新建工程,啥都不干,错误照旧。

    三、最后在MSDN里看LNK1123,有两中可能:1、文件损坏;2、文件无效致使转换成COFF失败。
    第一种可能可排除,引文新建工程也这样,文件无效也不可能——转换出了问题!~——对了,LNK时进行转换,而转换正是调用cvtres.exe实现的。

    四、启动搜索功能,找出电脑里所有的cvtres.exe,用PB下28K的换掉了CE500下16K的,编译OK!~

总结:1、由于第一个错误也是因为cvtres.exe,所以……大意
      2、LNK正是调用cvtres.exe把文件转换成COFF格式
      3、PB下的cvtres.exe,EVC也可以用——微软是一家啊!~

   

      

Failed to connect to the device Failed downloading

by:怀念放羊的日子

很期待这一刻:第一个EVC下写的“HelloWorld”与s3c2440开发板Linking成功并运行!~

1、安装ActiveSync使PC(调试机)与s3c2440(开发机)实现同步,文件同步;

2、EVC下Tools—>Configurate Platform Manager—>相应支持包
   Transpor:Microsoft ActiveSync
   Startup:Microsoft ActiveSync

3、And then……Build!!!!~出现问题了:Timeout: Failed to connect to the device Failed downloading

想不通——完全同步成功啊,PC上可实现开发板上文件的复制与删除……难道因为定制系统平台时少添加某个特性?难道……

本着尽快解决问题的思路,直接打电话给开发板提供商技术支持,她说的该注意的地方都没问题啊,不了了之……

本着有问题找百度的原则,看了一下午,结论:有鬼作怪,多是经过胡乱折腾后无意间就好了,不知道问什么,摸不到后脑勺……
有这样一个观点:Microsofe各应用程序之间的“家族”关系,涉及XP版本,Office 2003,Visio等,因为有可能存在某个“*.dll”
之间的共享依赖,安装与卸载无意间就改变了什么东西……暂且为止

最后找google,到处找资料,问题也慢慢清晰开来……程序跑起来了,嘿嘿,继续……

总结布步骤如下:go on……

4、To install the Microsoft Loopback Adapter in Microsoft Windows XP
a.Open Control Panel, choose Add Hardware, and then choose Next.
b.Choose Yes, I have already connected the hardware, and then choose Next.
c.From the Installed hardware list, select Add a new hardware device, and then choose Next.
d.Choose Install the hardware that I manually select from a list (Advanced), and then choose Next.
e.From the Common hardware types list, select Network adapters, and then choose Next.
f.From the Manufacturer list, select Microsoft.
g.From the Network Adapter list, select Microsoft Loopback Adapter, and then choose Next.
h.Choose Next, and then choose Finish

5、到开发板上在网络与拨号连接里面CS8900的那项IP设置为DHCP方式。

6、问题就这样解决了!!!~

目前我依旧晕……


  

fatal error CVT1102

by:怀念放羊的日子

EVC调试遇到下面问题:
Linking...
CVTRES : fatal error CVT1102: out of memory; 41 bytes required
LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt
Error executing link.exe.

解决办法: 把common/evc/bin下的cvtres.exe拷到evc/wince500/bin下代替

原因分析:版本不同