PowerButton驱动分析<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
DWORD
PBT_Init(DWORD dwContext)
{
DWORD IDPowerButtonThread;
DWORD IDResetButtonThread;
HMODULE hmCore;
//
// Obtain a pointer to the power manager function "SetSystemPowerState"
// from the core library so we can call into it.
//
pfnSetSystemPowerState = NULL;
hmCore = (HMODULE) LoadLibrary(_T("coredll.dll"));
if(hmCore != NULL)
{
pfnSetSystemPowerState = (PFN_SetSystemPowerState) GetProcAddress(hmCore, _T("SetSystemPowerState"));
if(pfnSetSystemPowerState == NULL)
{
FreeLibrary(hmCore);
}
}
// Initialize addresses now as opposed to when interrupts are handled so there are no race conditions
InitializeAddresses();//初始化硬件地址
// Create a thread to handle the power button event, and one to handle the reset button event.
ResetButtonIntrThreadHandle = CreateThread( //返回线程句柄
0,//必须为0
0, //忽略,线程堆栈大小由连接器设置决定
(LPTHREAD_START_ROUTINE)ResetButtonIntrThread,//指定线程函数名
0,
0,
&IDResetButtonThread //使用IDResetButtonThread接收线程标志符
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
DWORD IDPowerButtonThread;
|
if (ResetButtonIntrThreadHandle == 0)
{
RETAILMSG(1, (TEXT("PBT: CreateThread() Fail\r\n")));
}
PowerButtonIntrThreadHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) PowerButtonIntrThread, 0, 0, &IDPowerButtonThread);
if (PowerButtonIntrThreadHandle == 0)
{
RETAILMSG(1, (TEXT("PBT: CreateThread() Fail\r\n")));
}
return (dwContext);
}
static BOOL
InitializeAddresses(VOID)
{
BOOL RetValue = FALSE;
// IO Register Allocation
v_pIOPregs = (volatile S3C2410X_IOPORT_REG *)VirtualAlloc(
0, //分配内存的开始地址由系统指定
sizeof *v_pIOPregs,//分配内存大小
MEM_RESERVE,// 保留虚拟地址空间以便以后提交。
PAGE_NOACCESS//任何访问该区域的操作将被拒绝
);
if (v_pIOPregs == NULL)
{
ERRORMSG(1,(TEXT("PBT: VirtualAlloc failed!\r\n")));
} else {
if (
!VirtualCopy(//绑定一块物理内存到当前进程虚拟地址空间
(PVOID)v_pIOPregs, //指针,指向虚拟地址的起始地址
(PVOID)(S3C2410X_BASE_REG_PA_IOPORT >> 8), //物理地址右移8位。
sizeof *v_pIOPregs, //保留空间的大小
PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)//物理地址,可读可写,无缓存。
)
{
ERRORMSG(1,(TEXT("PBT: VirtualCopy failed!\r\n")));
VirtualFree((PVOID)v_pIOPregs, 0, MEM_RELEASE);
v_pIOPregs = NULL;
}
}
s2410INT = (volatile S3C2410X_INTR_REG *)VirtualAlloc(0, sizeof *s2410INT, MEM_RESERVE, PAGE_NOACCESS);
if (s2410INT == NULL)
{
ERRORMSG(1,(TEXT("PBT: VirtualAlloc failed!\r\n")));
} else {
if (!VirtualCopy((PVOID)s2410INT, (PVOID)(S3C2410X_BASE_REG_PA_INTR >> 8), sizeof *s2410INT, PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
{
ERRORMSG(1,(TEXT("PBT: VirtualCopy failed!\r\n")));
VirtualFree((PVOID)s2410INT, 0, MEM_RELEASE);
s2410INT = NULL;
}
}
EnableResetButtonInterrupt(VOID) { v_pIOPregs->GPFCON &= ~(0x3 << 4);// Set EINT2(GPF2) as EINT2 v_pIOPregs->GPFCON |= (0x2 << 4); v_pIOPregs->EXTINT0 &= ~(0x7 << 8);// Configure EINT2 as Falling Edge Mode v_pIOPregs->EXTINT0 |= (0x2 << 8); } |
{
RetValue = TRUE;
}
return (RetValue);
}
static DWORD
ResetButtonIntrThread(PVOID pArg)
{
EnableResetButtonInterrupt();配置寄存器状态
ResetButtonIntrEvent = CreateEvent( //创建事件, 成功返回一个事件对象句柄
NULL,//必须为NULL
FALSE,// 系统在等待线程被释放后自动重置状态为不可触发状态
FALSE,// 初始状态,为不可触发状态
NULL//创建事件对象没有名称
);
//
// Request a SYSINTR value from the OAL.
//
if (
!KernelIoControl( //根据IRQ获取一个SYSINTR
IOCTL_HAL_REQUEST_SYSINTR, //IO控制代码
&ResetButtonIrq, //指向一个缓冲区,其包含执行操作所必须的数据IRQ
static DWORD ResetButtonIrq = IRQ_EINT2; // Determined by SMDK2410 board layout. |
&ResetButtonSysIntr, //指向输出缓冲区,用来接收操作数据SYSINTR
Static DWORD ResetButtonSysIntr = SYSINTR_UNDEFINED; |
NULL
))
{
RETAILMSG(1, (TEXT("PBT: Error! Failed to request sysintr value for reset button interrupt.\r\n")));
return(0);
}
if (!(InterruptInitialize(//关联SYSINTR和之前创建的事件
ResetButtonSysIntr,// 虚拟中断标示符
ResetButtonIntrEvent, //当中断触发时,同时触发ResetButtonIntrEvent事件。
0, //不适用数据块
0 //数据块大小为0
)))
{
RETAILMSG(1, (TEXT("ERROR: ResetButton: Interrupt initialize failed.\r\n")));
}
// Handle power button presses.
for (;;)
{
WaitForSingleObject(//函数检查指定对象的当前状态。如果对象的状态为不可触发的。
//则调用线程进入一个高效率等待状态。在等待事件对象变为可触
//发或间隔时间超时,线程消耗很少的处理时间
ResetButtonIntrEvent, //指向事件的句柄
INFINITE//永不超时
);
//Mask the storage device interrupt EINT11 so we don't service it before reboot is finished
s2410INT->INTMSK = (s2410INT->INTMSK | (0x1 << 0x5));
if (ResetButtonIsPushed()) // Guard against noise triggering an interrupt.
{
//
// Soft reset and standard suspend-resume both start with suspend for now.
// Call whichever shutdown API is available.
//
if(pfnSetSystemPowerState != NULL)
{
RETAILMSG(1,(TEXT("PBT: Signalling power manager to reset...\r\n")));
pfnSetSystemPowerState(NULL, POWER_STATE_RESET, POWER_FORCE);
} else {
RETAILMSG(1,(TEXT("PBT: Resetting by calling KernelIoControl(IOCTL_HAL_REBOOT)...\r\n")));
KernelIoControl(IOCTL_HAL_REBOOT,NULL,0,NULL,0,NULL);
}
//
// Acquiesce to other threads since our work is complete as of
// the call to PowerOffSystem, or the signalling of the power
// manager.
//
Sleep(0);
}
else
RETAILMSG(1,(TEXT("PBT: Feeble button press or noise triggered it (ignored)\r\n")));
InterruptDone(ResetButtonSysIntr);//该函数通知内核中断处理完毕
}
}
总结:
中断驱动书写过程。
1. 设置物理地址到虚拟地址映射。因为wince启动后是对虚拟地址操作。InitializeAddresses
2. 创建一个线程。指定线程函数。获得线程句柄CreateThread
3. 配置GPIO口和中断寄存器状态。EnableResetButtonInterrupt
4. 创建一个事件。并初始化该事件为不可触发状态,自动触发。获得事件句柄CreateEvent
5. 根据IRQ获取一个SYSINTR KernelIoControl
6. 初始化,关联SYSINTR和之前创建的事件InterruptInitialize
7. 等待事件触发WaitForSingleObject
8. 处理中断进程
9. 通知内核中断处理完毕InterruptDone
文章评论(0条评论)
登录后参与讨论