原创 PowerButton驱动分析

2009-9-18 14:53 3600 13 13 分类: MCU/ 嵌入式

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);


}

    if(v_pIOPregs && s2410INT)


    {


      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.

sizeof ResetButtonIrq,      //缓冲区的大小


&ResetButtonSysIntr, //指向输出缓冲区,用来接收操作数据SYSINTR





Static DWORD ResetButtonSysIntr = SYSINTR_UNDEFINED;

sizeof ResetButtonSysIntr, //定输出缓冲区的大小


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


c6242254-8805-47bf-b199-b59e5ccdb09a.JPG

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
13
关闭 站长推荐上一条 /3 下一条