Re: 请教并请求加入论坛

8 views
Skip to first unread message

gooogleman

unread,
Dec 4, 2009, 7:17:01 PM12/4/09
to bad_boy, gooogleman
deviceiocontrol函数可以实现和应用程序通信。嘿嘿。

2009/12/5 gooogleman <wogoyi...@gmail.com>
deviceiocontrol函数可以实现和应用程序通信。嘿嘿。

2009/11/25 bad_boy <wuxiao...@163.com>

gooogleman版主:
     你好,我刚毕业出来,现在在一家广州天河公司从事嵌入式软件开发。之前培训过Linux嵌入式系统,后来公司主要平台是WinCE,所以对
于我来说完全是刚上手。现在我有个WinCE按键驱动的问题(早在2009年2月份csdn论坛上有人问过类似问题)想问您:我这边有5个按键接在
PXA270的GPIO上,通过上拉电阻上拉,当无按键按下时GPIO上为高电平,当有按键按下时GPIO上为低电平。我这里仿造三星
pwrbtn2410电源管理驱动程序写了一个驱动,但对于多个按键情况如何实现以及当有键按下时,如何发送消息给上层应用软件?不是很明白。 悉心等
待你的指导!
附件是一个按键情况的驱动:
#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)
{
  ;
}





--
销售2440/6410/2450开发板,联系方式QQ:402955982,博客;http://blog.csdn.net/gooogleman
gooogleman嵌入式网店http://shop59480987.taobao.com/
技术支持论坛http://groups.google.com/group/gooogleman?hl=zh-CN
关于技术问题,请到上面论坛发帖,我邮箱会收到问题的。如果下次再有人问到相同的问题,就可以直接在论坛转发答案给他们了,好玩吧。我有信心可以把这个论坛搞好——靠大家的支持了!
关于技术问题,我会24小时之内回复(节假日除外),即使我不懂,但是我一定会看,帮顶,嘿嘿。
                                    gooogleman(wogoyixikexie@gliet)







--
销售2440/6410/2450开发板,联系方式QQ:402955982,博客;http://blog.csdn.net/gooogleman
gooogleman嵌入式网店http://shop59480987.taobao.com/
技术支持论坛http://groups.google.com/group/gooogleman?hl=zh-CN
关于技术问题,请到上面论坛发帖,我邮箱会收到问题的。如果下次再有人问到相同的问题,就可以直接在论坛转发答案给他们了,好玩吧。我有信心可以把这个论坛搞好——靠大家的支持了!
关于技术问题,我会24小时之内回复(节假日除外),即使我不懂,但是我一定会看,帮顶,嘿嘿。
                                    gooogleman(wogoyixikexie@gliet)




Reply all
Reply to author
Forward
0 new messages