yangtch的个人空间 https://blog.eetop.cn/562 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

硬件工程师眼中的WINCE 键盘驱动的自定义修改(1)

已有 2828 次阅读| 2010-8-17 00:22 |个人分类:WINCE

硬件工程师眼中的WINCE 键盘驱动的自定义修改

最近有个项目需要弄弄WINCE,趁机玩玩。由于自己偏重于硬件,一般不喜欢自己搭程序框架 (其实是功力不够,心虚的表现),总是希望借助现有的框架,修修补补,符合自己使用就行。主要关注修改的关键点和如何修改,系统的运行机理不是我所重点研究的范畴。就像把IBM换成LENOVL,就变成了中国品牌,我只知道怎么贴标签,贴在哪里就行,而不管Thinkpad里面是怎么做的。刚刚搞定了WINCE的键盘驱动,趁着手热写下这些文字,希望能有用。

如果你也是一个像我一样的初学者,也请在现有的框架上修改。

为了避免广告嫌疑,开发板就定为SMDK2440吧软件环境PB5

键盘驱动位于C:\WINCE500\PLATFORM\SMDK2440A\Src\Drivers\Keybd文件夹下,首先从键盘驱动的加载入口点开始。

..\Keybd\ Kbdcommon 下包含文件kbd.cpp包含有键盘驱动的入口地址,Matrix_Entry()。要想了解键盘驱动的整个加载过程,必须从Matrix_Entry()函数入手。

 

1. Matrix_Entry()函数的几个主要工作流程:

if (v_pp2k->Initialize())

{

   v_pp2k ->IsrThreadStart();

}

Else

 {

    ERRORMSG(1,(TEXT("Could not initialize ps2 keyboard.\r\n")));

    delete v_pp2k;

     v_pp2k = NULL;

}

 

变量v_pp2k 是个全局变量,定义为Ps2Keybd       *v_pp2k; 从名字可以看出Ps2Keybd是个类,定义了针对键盘操作的一些函数,定义在s3c2440kbd.hpp中。

代码首先执行键盘初始化工作,if (v_pp2k->Initialize())中可以对硬件配置进行操作,例如采用键盘阵列,配置IO端口以及中断方式;如果采用专属芯片(SMDK2440),可以进行初始化芯片寄存器等。

初始化成功之后则启动线程v_pp2k ->IsrThreadStart();具体实现细节后文详细分析。

 

if (!KeybdDriverInitializeAddresses())

{

              goto leave;

}

     KeybdDriverInitializeAddresses()函数被调用,该函数给键盘驱动分配内存空间。为何大费周折,进行一个系统调用?里面太深层次的问题没有仔细研究,实际上就是给几个struct分配物理地址(物理地址是真实存在的,对应于SDRAM的内存中的一块区域)。

 

if (v_pp2k)

{

       v_pp2k->KeybdPowerOn();

}

     这个也好理解,给你一个上电启动的机会(是否可以和v_pp2k->Initialize()合并在一起??)

如果足够幸运,上述流程都走了一遍,此时就可以执行Matrix_Entry()函数的返回 

fRet = TRUE;

             

leave:

    DEBUGMSG(ZONE_INIT, (_T("%s: Initialization complete\r\n"), pszFname));

       return fRet;

 

让我们理一理Matrix_Entry()到底干了什么,初始化->创建线程->分配物理空间->上电->退出。好像确实没干什么东西。那么作为一个硬件工程师,此时带给我的疑问:

1 中断怎么挂接到驱动中的;

2 何时在那个函数中读取键盘扫描码,又如何送给操作系统;

3键盘扫描码该如何与操作系统的码字对应起来。

 

回头看看Matrix_Entry()函数,对于上面三个问题没有一个给出答案,而我们唯一不清楚的就是IsrThreadStart()到底干了什么,不过从字面上理解就应当是启动(START)中断服务程序(ISR)线程(Thread)。好吧,让我们进入到IsrThreadStart()内部去看看他的所以然。

 

2. IsrThreadStart()函数分析:

BOOL Ps2Keybd::IsrThreadStart()

{

       HANDLE hthrd;

 

       DEBUGMSG(1,(TEXT("IsrThreadStart:\r\n")));

       hthrd = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Ps2KeybdIsrThread,this,0,NULL);

       //     Since we don't need the handle, close it now.

       CloseHandle(hthrd);

       return TRUE;

}

真是人如其名 IsrThreadStart ()只干了一件事,创建Ps2KeybdIsrThread()线程,激动的心再次莫名的跌落。还好保留了一丝线索,让我们去看看创建的Ps2KeybdIsrThread()去干了什么吧,别忘记上面的三个问题。

 

3. Ps2KeybdIsrThread()分析

 

DWORD Ps2KeybdIsrThread(Ps2Keybd *pp2k)

{

       DEBUGMSG(1,(TEXT("Ps2KeybdIsrThread:\r\n")));

       pp2k->IsrThreadProc();

       return 0;

}

大哥,有意思么,又是什么没干,算了不说了,去看看IsrThreadProc(),字面意思中断服务(ISR)线程(THREAD)处理(PROC)

 

4. IsrThreadProc()分析

先贴码子:

 

BOOL Ps2Keybd::IsrThreadProc()

{

       DWORD dwPriority;

    DWORD dwIrq_Keybd = 0;

 

       // look for our priority in the registry -- this routine sets it to zero if

       // it can't find it.

       ReadRegDWORD( TEXT("HARDWARE\\DEVICEMAP\\KEYBD"), _T("Priority256"), &dwPriority );

       if(dwPriority == 0) {

              dwPriority = 240;   // default value is 145

       }

 

    DEBUGMSG(1, (TEXT("IsrThreadProc:\r\n")));

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

    if (m_hevInterrupt == NULL) {

        DEBUGMSG(1, (TEXT("IsrThreadProc: InterruptInitialize\r\n")));

              goto leave;

       }

 

       ReadRegDWORD( TEXT("HARDWARE\\DEVICEMAP\\KEYBD"), _T("Irq"), &dwIrq_Keybd );

 

    // Call the OAL to translate the IRQ into a SysIntr value.

    //

    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIrq_Keybd, sizeof(DWORD), &g_dwSysIntr_Keybd, sizeof(DWORD), NULL))

    {

        DEBUGMSG(1, (TEXT("ERROR: Failed to obtain sysintr value for keyboard interrupt.\r\n")));

        g_dwSysIntr_Keybd = SYSINTR_UNDEFINED;

        goto leave;

    }

 

       if (!InterruptInitialize(g_dwSysIntr_Keybd,m_hevInterrupt,NULL,0)) {

              DEBUGMSG(1, (TEXT("IsrThreadProc: KeybdInterruptEnable\r\n")));

              goto leave;

       }

 

       // update the IST priority

       CeSetThreadPriority(GetCurrentThread(), (int)dwPriority);

 

       extern UINT v_uiPddId;

       extern PFN_KEYBD_EVENT v_pfnKeybdEvent;

 

       KEYBD_IST keybdIst;

       keybdIst.hevInterrupt = m_hevInterrupt;

       keybdIst.dwSysIntr_Keybd = g_dwSysIntr_Keybd;

       keybdIst.uiPddId = v_uiPddId;

       keybdIst.pfnGetKeybdEvent = KeybdPdd_GetEventEx2;

       keybdIst.pfnKeybdEvent = v_pfnKeybdEvent;

             

       KeybdIstLoop(&keybdIst);

 

leave:

    return 0;

}

看上去好像有货,一点点看吧。先看第一句,

ReadRegDWORD( TEXT("HARDWARE\\DEVICEMAP\\KEYBD"), _T("Priority256"), &dwPriority );

GOOGLE了一下ReadRegDWORD(),字面意思读取(READ)注册表(REG)DWORD型的数据,注册表路径"HARDWARE\\DEVICEMAP\\KEYBD",子建"Priority256",放到dwPriority里面。注册表信息在platform.reg中可以查到。

[HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\KEYBD]

    "DriverName"="kbdmouse.dll"

    "Irq"=dword:1

    "IOBase"=dword:B1600000

    "SSPBase"=dword:B1900000

好像没有"Priority256"子键啊,算了,就是一个优先级的事情不管了,先知道意思就行了。接着往下看m_hevInterrupt = CreateEvent(NULL,FALSE,FALSE,NULL);建立了一个 事件(event),从字面上看不出来是干什么的。为什么要建立这个事件呢。在嵌入式系统中,中断处理一般方式为,触发中断->中断响应->触发中断对应的事件(isrevent)->中断退出->等待isrevent的进行执行->具体的中断处理程序。这样做的目的就是为了尽量减少中断的处理时间。该时间创建应当为相同目的

ReadRegDWORD( TEXT("HARDWARE\\DEVICEMAP\\KEYBD"), _T("Irq"), &dwIrq_Keybd );

读取了一个Irq中断号到dwIrq_Keybd变量中,是不是和问题1联系上了?"Irq"=dword:1原来 中断号是1,是不是对应于物理中断?看来只能求助于SMDK2440的原理图了。看看下图1 2,网络号KBDINTU24产生的中断信号,确实与S3C2440EINT1连接,对照S3C2440手册的第14章,EINT1对应于中断号1,看来"Irq"=dword:1确实是物理中断号。

接着看,KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIrq_Keybd, sizeof(DWORD), &g_dwSysIntr_Keybd, sizeof(DWORD), NULL),这个函数网上又很多说法,个人感觉是申请了一个系统中断号g_dwSysIntr_Keybd,并把系统中断号与物理中断号对应起来。

InterruptInitialize(g_dwSysIntr_Keybd,m_hevInterrupt,NULL,0),把系统中断号与刚刚建立的事件挂接起来。

CeSetThreadPriority(GetCurrentThread(), (int)dwPriority);设置线程的优先级。

到此我们解决了第一个问题,总结一下,首先从注册表中读取到中断号1,这个中断号实际上与硬件结构密切相关;然而在WINCE系统下,是不能直接调用物理中断号,因此需要申请一个WINCE提供的系统中断号,并将系统中断号与物理中断号对应起来。最后建立系统中断号与用于中断事件的联系。

图1

图2

 


点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 1

    粉丝
  • 0

    好友
  • 0

    获赞
  • 9

    评论
  • 363

    访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-5-4 18:19 , Processed in 0.032031 second(s), 14 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部