分享

WinCE的中断流驱动程序原理概要-代码分析【转】

 lhzstudio 2012-05-09

转自 http://flyswordfly.blog.163.com/blog/static/1436663620082116329336/

/* 程序开始定义包含的头文件及定义需要的全局变量*/

#include <windows.h>

#include <types.h>

#include <excpt.h>

#include <tchar.h>

#include <cardserv.h>

#include <cardapi.h>

#include <tuple.h>

#include <devload.h>

#include <diskio.h>

#include <nkintr.h>

#include <windev.h>

#include "bulverde.h" //定义了PXA270的寄存器地址等

#define PRIVATE    static

#define PUBLIC

/* 读按键事件*/

PRIVATE HANDLE gReadKeyEvent[2];

/*定义了一个读按键事件数组,当按下按键时,中断服务线程IST通过事件 gReadKeyEvent[0]通知本驱动的读函数KEY_Read():按键按下;当本驱动退出或卸载时,通过事件gReadKeyEvent[1] 通知读函数KEY_Read():驱动已经关闭或卸载。*/

/* 按键按下中断事件*/

PRIVATE HANDLE gWaitEvent;

/* 是否退出中断服务线程*/

PRIVATE UINT32 g_bKillIST = FALSE;

/*此处定义了一个全局变量g_bKillIST,它用于当驱动卸载时通知中断服务线程退出,这样才能完全卸载驱动*/

/* 中断处理线程*/

PRIVATE HANDLE gEINTIntrThread;

/* 驱动打开计数器*/

PRIVATE UINT32 gOpenCount = 0;

/* EINT的物理中断号及逻辑中断号*/

PRIVATE UINT32 g_EINTIrq = XLLP_INTC_GPIOXX_2;

PRIVATE UINT32 g_EINTSysIntr = SYSINTR_UNDEFINED;

/* GPIO寄存器对应的虚拟地址,定义了一个处理器GPIO相关寄存器的结构体变量,该结构体的定义在xllp_gpio.h头文件中。其他全局变量在使用时说明*/

PRIVATE volatile XLLP_GPIO_T * v_pGPIOReg;

/* 中断寄存器对应的虚拟地址,定义了一个处理器的中断寄存器的结构体变量,该结构体的定义在xllp_intc.h头文件中。其他全局变量在使用时说明*/

PRIVATE volatile XLLP_INTC_T * v_pICReg;

/* 驱动动态库入口函数*/

BOOL WINAPI DllEntry (HANDLE hInstDll,DWORD dwReason,LPVOID lpvReserved)

{

switch(dwReason)

{

   case DLL_PROCESS_ATTACH:

   RETAILMSG(1,(TEXT("Key:DLL_PROCESS_ATTACH.\r\n")));

   DisableThreadLibraryCalls((HMODULE)hInstDll);

   break;//挂载成功

   case DLL_PROCESS_DETACH:

   RETAILMSG(1,(TEXT("Key:DLL_PROCESS_DETACH.\r\n")));

   break;//卸载成功

}

return (TRUE);

}

/* 申请GPIO寄存器地址对应的虚拟空间,在WinCE中,程序访问的地址都是虚地址,因此,要访问硬件物理地址,必须将物理地址空间映射到虚拟地址空间*/

PRIVATE BOOL EINT_InitializeAddresses(VOID)

{

BOOL RetValue = TRUE;

RETAILMSG(1,(TEXT(">>>EINT_initalization address..set..\r\n")));

/* IO Register Allocation,VirtualAlloc()函数的功能是申请一块虚拟内存空间,该空间的大小为sizeof(PXA270寄存器结构体的大小),*/

v_pGPIOReg = (volatile XLLP_GPIO_T *)VirtualAlloc(0,sizeof(XLLP_GPIO_T),MEM_RESERVE,PAGE_NOACCESS);

if (v_pGPIOReg ==NULL)

{

   ERRORMSG(1,(TEXT("For IOPregs : VirtualAlloc failed! \r\n")));

   RetValue = FALSE;

}

else

{

/*VirtualCopy()函数的功能是将VirtualAlloc()函数申请的虚拟空间(起始地址为v_pGPIOReg)映射到GPIO寄存器的物理地址,经过映射后,通过全局变量指针v_pGPIOReg就可以访问GPIO寄存器了*/

   if(! VirtualCopy((PVOID)v_pGPIOReg,(PVOID)(0x40E00000>>8),

     sizeof(XLLP_GPIO_T),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_pGPIOReg)

   {

    VirtualFree((PVOID)v_pGPIOReg,0,MEM_RELEASE);

   }

   v_pGPIOReg = NULL;

}

else

   RETAILMSG(1,(TEXT(":::EINT_InitializeAddresses - Success\r\n")));

return (RetValue);

}

/* 编写配置EINT(GPIO100)引脚为外部中断引脚,这里示例了如何操作硬件寄存器:*/

PRIVATE VOID EINT_ConfigInterruptPin(VOID)

{

v_pGPIOReg->GPDR2 &=~( 0x1<<30 );//XLLP_GPIO_BIT_KP_MKIN1,设置方向寄存器

v_pGPIOReg->GRER2 |=( 0x1<<30 );//使能上升沿中断

v_pGPIOReg->GFER2 &=~( 0x1<<30 );//禁止下降沿中断

v_pGPIOReg->GAFR2_U &=~( 0x3<<28);//设置为通用的IO口

v_pICReg->icmr |=( 0x1<<10 );//开屏蔽中断位

v_pICReg->iclr &=~( 0x1<<10 );//中断被传递到IRQ中断输入

v_pICReg->iccr |=0x01;        //没有被屏蔽的中断才能将处理器从空闲状态中唤醒

v_pICReg->ipr[10] =0x8000000a;

;

}

PRIVATE BOOL Key_IsPushed(VOID)

{

return ((v_pGPIOReg->GEDR2&(1<<30)?TRUE:FALSE));//??????

}

PRIVATE VOID EINT_ConfigPinDefault(VOID)

{

v_pGPIOReg->GEDR2|=(1<<30);

}

DWORD EINTKey_IntrThread(PVOID pArg)

{

DWORD ret;

/*创建外部中断事件,用于ISR通知ISR外部中断触发,然后调用内核函数InterruptInitialize()

将逻辑中断号g_EINTSysIntr与事件gWaitEvent关联起来,并使能该中断,当该中断触发时,ISR就

触发事件gWaitEvent生效,完成以上工作,该线程就进行无限循环,等待事件生效;*/

gWaitEvent = CreateEvent(NULL,FALSE,FALSE,NULL);

//初始化外部按键中断:注册外部中断事件,允许外部中断

if ( !( InterruptInitialize(g_EINTSysIntr,gWaitEvent,0,0)))

{

   RETAILMSG(1,(TEXT("ERROR:EINTKey:InterruptInitialize failed.\r\n")));

   CloseHandle(gWaitEvent);

   return 0;

}

while (1)

{

   ret = WaitForSingleObject(gWaitEvent,INFINITE);

   if ( (ret == WAIT_OBJECT_0)&&(g_bKillIST == FALSE))

   {

    if(Key_IsPushed())

    {

     Sleep(20);        //延时20ms用于滤去噪声

     if (Key_IsPushed()) //外部中断按键确实已经按下

     {

     SetEvent(gReadKeyEvent[0]); //通知读函数,外部中断按键按下

     RETAILMSG(1,(TEXT(":::The Key1 Pushed.\r\n")));

                 //EINT_ConfigPinDefault();

     }

   

    }

   }

   else

   {

   CloseHandle(gWaitEvent);

      RETAILMSG(1,(TEXT(":::EINTKey_IntrThread Exit.\r\n")));

   return 0;

   }//if (ret != WAIT_OBJECT_0) or Error occurs

   InterruptDone(g_EINTSysIntr);//通知内核,中断处理结束

}

return 1;

}

/*流驱动接口函数的初始化函数,该函数的主要工作是进行外部中断引脚的初始化,申请的逻辑中断号并保存到全局变量*/

DWORD KEY_Init(DWORD dwContext)

{

DWORD IDThread;

//取得GPIO相关寄存器的虚拟地址空间

if ( EINT_InitializeAddresses() == FALSE )

return 0;

//使能EINT引脚为中断引脚,并为上升沿触发

EINT_ConfigInterruptPin();

//从OAL请求一个SYSINTR值

if( ! KernelIoControl( IOCTL_HAL_REQUEST_SYSINTR,&g_EINTIrq,sizeof(UINT32),

                    &g_EINTSysIntr,sizeof(UINT32),NULL))

{

  

   RETAILMSG(1,(TEXT("ERROR:EINTKey:Failed to request sysintr value for EINT interrupt.\r\n")));

   return(0);

}

RETAILMSG(1,(TEXT("INFO:EINTKey:Mapped Irq 0x%x to SysIntr 0x%x.\r\n"),g_EINTIrq,g_EINTSysIntr));

//创建一个外部中断处理线程IST

gEINTIntrThread = CreateThread(0,0,(LPTHREAD_START_ROUTINE)EINTKey_IntrThread,0,0,&IDThread);

if ( gEINTIntrThread == NULL )

{

   RETAILMSG(1,(TEXT(":::KEY_Init:CreateThread()Fail.\r\n")));

   KernelIoControl( IOCTL_HAL_RELEASE_SYSINTR,&g_EINTIrq,sizeof(UINT32),

                    NULL,0,NULL);

   return 0;

}

gReadKeyEvent[0] = CreateEvent(NULL,FALSE,FALSE,NULL);

gReadKeyEvent[1] = CreateEvent(NULL,FALSE,FALSE,NULL);

RETAILMSG(1,(TEXT(":::KEY_Init Sucessfully!\r\n")));

//返回不为0的数

return (DWORD)gEINTIntrThread;

}

DWORD KEY_Open(DWORD hDeviceContext,DWORD AccessCode,DWORD ShareMode)

{

if ( gOpenCount > 0 )//本驱动只允许单一访问

       return 0;

gOpenCount++;

return gOpenCount;   //返回一个不为零的数

}

DWORD KEY_Read(DWORD Handle,LPVOID pBuffer,DWORD dwNumBytes)

{

DWORD ret;

uchar * pReadBuffer;

if (( pBuffer == NULL ) || (dwNumBytes <= 0 ))

   return 0;

pReadBuffer = MapPtrToProcess(pBuffer,GetCallerProcess());

* pReadBuffer = 0;

/*挂起当前线程,直到KEY1按键按下或驱动关闭*/

ret = WaitForMultipleObjects(2,gReadKeyEvent,FALSE,INFINITE);

if ( ret == WAIT_OBJECT_0)

{

   ResetEvent(gReadKeyEvent[0]);

   * pReadBuffer = 1;

   return 1;

}

else if( ret == ( WAIT_OBJECT_0 + 1 ) )

{

   ResetEvent(gReadKeyEvent[1]);

   * pReadBuffer = 0;

   return 1;

}

return 0;

}

BOOL KEY_Close(DWORD Handle)

{

if ( gOpenCount > 0 )

   SetEvent(gReadKeyEvent[1]);//通知读函数线程驱动已经关闭

gOpenCount = 0;

return TRUE;

}//KEY_Close

BOOL KEY_Deinit(DWORD dwContext)

{

SetEvent(gWaitEvent);//通知中断服务线程退出

g_bKillIST = TRUE;

Sleep(200);          //等待中断服务线程退出

SetEvent(gReadKeyEvent[1]);//通知读函数线程驱动已经关闭

    //释放中断资源

InterruptDone(g_EINTSysIntr);

InterruptDisable(g_EINTSysIntr);

KernelIoControl( IOCTL_HAL_RELEASE_SYSINTR,&g_EINTSysIntr,sizeof(UINT32),

                    NULL,0,NULL);

//恢复外部中断引脚为输入GPIO

//EINT_ConfigPinDefault();

//释放申请的虚拟空间

if (v_pGPIOReg)

   VirtualFree((PVOID)v_pGPIOReg,0,MEM_RELEASE);

gOpenCount = 0;

CloseHandle(gReadKeyEvent[0]);

CloseHandle(gReadKeyEvent[1]);

return TRUE;

}

DWORD KEY_Write(DWORD hOpenContext,LPCVOID pBuffer,DWORD Count)

{

return 0;

}

DWORD KEY_Seek(DWORD hOpenContext,long Amount ,DWORD Type)

{

return 0;

}

BOOL KEY_IOControl(DWORD hOpenContext,

      DWORD dwCode ,

      PBYTE pBufIn,

      DWORD dwLenIn,

      PBYTE pBufOut,

      DWORD dwLenOut,

      PDWORD pdwActualOut)

{

return FALSE;

}

void KEY_PowerUp(void)

{

   ;

}

void KEY_PowerDown(void)

{

   ;

}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多