以前在CSDN写过一些wince5.0中断的文章,现在重新看看,发现以前的有些理解是错误的,想翻开来改改,可是郁闷的CSDN在前台没有返回后台的编辑功能,所以现在重新写一篇纠正一下。
首先描述wince5.0 (2440BSP)的中断流程
注册表等——》KernelIoControl(——》OEMIoControl——》OALIntrRequestIrqs )把物理中断转换成系统中断——》InterruptInitialize调用OEMInterruptEnable使能中断并用中断绑定线程——》OEMInterruptHandler屏蔽中断——》执行线程——》InterruptDone——》调用OEMInterruptDone——》调用OALIntrDoneIrqs完成中断线程并重新使能中断
现在看来,5.0BSP和4.2BSP的中断并没有太大差别,一个是动态,一个是静态,OEMInterruptEnable,OEMInterruptHandler函数位置不一样而已——有空看看中断的汇编部分和PB帮助,那么一切都会明了。
File: oem.c
1 //
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //
4 //
5 // Use of this source code is subject to the terms of the Microsoft end-user
6 // license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
7 // If you did not accept the terms of the EULA, you are not authorized to use
8 // this source code. For a copy of the EULA, please see the LICENSE.RTF on your
9 // install media.
10 //
11 //------------------------------------------------------------------------------
12 //
13 // File: oem.c
14 //
15 // This file implements a standard implementation of OEMInterrupt functions
16 // relating to enabling, disabling and finishing interrupts.
17 //
18 #include <windows.h>
19 #include <nkintr.h>
20 #include <oal.h>
21
22
23 //------------------------------------------------------------------------------
24 //
25 // Function: OEMInterruptEnable
26 //
27 // This function enables the IRQ given its corresponding SysIntr value.
28 // Function returns true if SysIntr is valid, else false.
29 //
30 BOOL OEMInterruptEnable(DWORD sysIntr, LPVOID pvData, DWORD cbData)
31 {
32 BOOL rc = FALSE;
33 const UINT32 *pIrqs;
34 UINT32 count;
35
36 OALMSG(OAL_INTR&&OAL_VERBOSE,
37 (L"+OEMInterruptEnable(%d, 0x%x, %d)\r\n", sysIntr, pvData, cbData
38 ));
39
40 // SYSINTR_VMINI & SYSINTR_TIMING are special cases
41 if (sysIntr == SYSINTR_VMINI || sysIntr == SYSINTR_TIMING) {
42 rc = TRUE;
43 goto cleanUp;
44 }
45
46 // Obtain the SYSINTR's underlying IRQ number
47 if (!OALIntrTranslateSysIntr(sysIntr, &count, &pIrqs)) {
48 // Indicate invalid SysIntr
49 OALMSG(OAL_ERROR, (
50 L"ERROR: OEMInterruptEnable: IRQs are undefined for SysIntr %d\r\n",
51 sysIntr
52 ));
53 goto cleanUp;
54 }
55
56 // Enable the interrupt
57 rc = OALIntrEnableIrqs(count, pIrqs);
58
59 cleanUp:
60 OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OEMInterruptEnable(rc = 1)\r\n"));
61 return rc;
62 }
63
64
65 //------------------------------------------------------------------------------
66 //
67 // Function: OEMInterruptDisable(DWORD sysIntr)
68 //
69 // This function disables the IRQ given its corresponding SysIntr value.
70 //
71 //
72 VOID OEMInterruptDisable(DWORD sysIntr)
73 {
74 const UINT32 *pIrqs;
75 UINT32 count;
76
77 OALMSG(OAL_INTR&&OAL_VERBOSE, (L"+OEMInterruptDisable(%d)\r\n", sysIntr));
78
79 // Obtain the SYSINTR's underlying IRQ number
80 if (!OALIntrTranslateSysIntr(sysIntr, &count, &pIrqs)) {
81 // Indicate invalid SysIntr
82 OALMSG(OAL_ERROR, (
83 L"ERROR: OEMInterruptEnable: IRQs are undefined for SysIntr %d\r\n",
84 sysIntr
85 ));
86 goto cleanUp;
87 }
88
89 // Disable the interrupt
90 OALIntrDisableIrqs(count, pIrqs);
91
92 cleanUp:
93 // Indicate exit
94 OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OEMInterruptDisable\r\n"));
95 }
96
97
98 //------------------------------------------------------------------------------
99 //
100 // Function: OEMInterruptDone
101 //
102 // OEMInterruptDone is called by the kernel when a device driver
103 // calls InterruptDone(). The system is not preemtible when this
104 // function is called.
105 //
106 VOID OEMInterruptDone(DWORD sysIntr)
107 {
108 const UINT32 *pIrqs;
109 UINT32 count;
110
111 OALMSG(OAL_INTR&&OAL_VERBOSE, (L"+OEMInterruptDone(%d)\r\n", sysIntr));
112 if (OALIntrTranslateSysIntr(sysIntr, &count, &pIrqs)) {
113 OALIntrDoneIrqs(count, pIrqs);
114 }
115 OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OEMInterruptDone\r\n"));
116 }
117
118 //------------------------------------------------------------------------------
119
看OALIntrTranslateSysIntr,
OALIntrTranslateSysIntr
1 //------------------------------------------------------------------------------
2 //
3 // Function: OALIntrTranslateSysIntr
4 //
5 // This function maps a SYSINTR to its corresponding IRQ. It is typically used
6 // in OEMInterruptXXX to obtain IRQs for given SYSINTR.
7 //
8 BOOL OALIntrTranslateSysIntr(
9 UINT32 sysIntr, UINT32 *pCount, const UINT32 **ppIrqs
10 ) {
11 BOOL rc;
12
13 OALMSG(OAL_INTR&&OAL_VERBOSE, (L"+OALTranslateSysIntr(%d)\r\n", sysIntr));
14
15 // Valid SYSINTR?
16 if (sysIntr >= SYSINTR_MAXIMUM) {
17 rc = FALSE;
18 goto cleanUp;
19 }
20 *pCount = 1;
21 *ppIrqs = &g_oalSysIntr2Irq[sysIntr];
22 rc = TRUE;
23
24 cleanUp:
25 OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OALTranslateSysIntr(rc = %d)\r\n", rc));
26 return rc;
27 }
28
从上面的代码可以知道,以前说这个系统中断数目限制是从哪里来的SYSINTR_MAXIMUM是系统限定了。
不知道系统为什么要做这个限制,我想如果想改动,也是可行的。不过我觉得有点奇怪,这个中断相关的g_oalIrq2SysIntr是怎么回事呢
static UINT32 g_oalSysIntr2Irq[SYSINTR_MAXIMUM];
static UINT32 g_oalIrq2SysIntr[OAL_INTR_IRQ_MAXIMUM];
我原以为是个全局数组,现在看来,还是另有玄机。现在看看g_oalIrq2SysIntr这些到底在哪里被修改过了,就知道这是怎么来的了
Code
1 //------------------------------------------------------------------------------
2 // 刚开始的时候,g_oalSysIntr2Irq和g_oalIrq2SysIntr都是初始化为未定义的
3 // Function: OALIntrMapInit
4 //
5 // This function must be called from OALInterruptInit to initialize mapping
6 // between IRQ and SYSINTR. It simply initialize mapping arrays.
7 //
8 VOID OALIntrMapInit()
9 {
10 UINT32 i;
11
12 OALMSG(OAL_FUNC&&OAL_INTR, (L"+OALIntrMapInit\r\n"));
13
14 // Initialize interrupt maps
15 for (i = 0; i < SYSINTR_MAXIMUM; i++) {
16 g_oalSysIntr2Irq[i] = OAL_INTR_IRQ_UNDEFINED;
17 }
18 for (i = 0; i < OAL_INTR_IRQ_MAXIMUM; i++) {
19 g_oalIrq2SysIntr[i] = SYSINTR_UNDEFINED;
20 }
21
22 OALMSG(OAL_FUNC&&OAL_INTR, (L"-OALIntrMapInit\r\n"));
23 }
24
25 //------------------------------------------------------------------------------
26 // 静态映射中断 在2440 5.0BSP没有使用到
27 // Function: OALIntrStaticTranslate
28 //
29 // This function sets static translation between IRQ and SYSINTR. In most
30 // cases it should not be used. Only exception is mapping for
31 // SYSINTR_RTC_ALARM and obsolete device drivers.
32 //
33 VOID OALIntrStaticTranslate(UINT32 sysIntr, UINT32 irq)
34 {
35 OALMSG(OAL_FUNC&&OAL_INTR, (
36 L"+OALIntrStaticTranslate(%d, %d)\r\n", sysIntr, irq
37 ));
38 if (irq < OAL_INTR_IRQ_MAXIMUM && sysIntr < SYSINTR_MAXIMUM) {
39 g_oalSysIntr2Irq[sysIntr] = irq;
40 g_oalIrq2SysIntr[irq] = sysIntr;
41 }
42 OALMSG(OAL_FUNC&&OAL_INTR, (L"-OALIntrStaticTranslate\r\n"));
43 }
44
45 //------------------------------------------------------------------------------
46 // 这个函数作用很大,把物理中断转换成系统中断
47 // Function: OALIntrRequestSysIntr
48 //
49 // This function allocate new SYSINTR for given IRQ and it there isn't
50 // static mapping for this IRQ it will create it.
51 //
52 UINT32 OALIntrRequestSysIntr(UINT32 count, const UINT32 *pIrqs, UINT32 flags)
53 {
54 UINT32 irq, sysIntr;
55
56 OALMSG(OAL_INTR&&OAL_FUNC, (
57 L"+OALIntrRequestSysIntr(%d, 0x%08x, 0x%08x)\r\n", count, pIrqs, flags
58 ));
59
60 // Valid IRQ?
61 if (count != 1 || pIrqs[0] >= OAL_INTR_IRQ_MAXIMUM) {
62 sysIntr = SYSINTR_UNDEFINED;
63 goto cleanUp;
64 }
65 irq = pIrqs[0];
66
67 // If there is mapping for given irq check for special cases
68 if (g_oalIrq2SysIntr[irq] != SYSINTR_UNDEFINED) {
69 // If static mapping is requested we fail
70 if ((flags & OAL_INTR_STATIC) != 0) {
71 OALMSG(OAL_ERROR, (L"ERROR: OALIntrRequestSysIntr: "
72 L"Static mapping for IRQ %d already assigned\r\n", irq
73 ));
74 sysIntr = SYSINTR_UNDEFINED;
75 goto cleanUp;
76 }
77 // If we should translate, return existing SYSINTR
78 if ((flags & OAL_INTR_TRANSLATE) != 0) {
79 sysIntr = g_oalIrq2SysIntr[irq];
80 goto cleanUp;
81 }
82 }
83
84 // Find next available SYSINTR value
85 for (sysIntr = SYSINTR_FIRMWARE; sysIntr < SYSINTR_MAXIMUM; sysIntr++) {
86 if (g_oalSysIntr2Irq[sysIntr] == OAL_INTR_IRQ_UNDEFINED) break;
87 }
88
89 // Any available SYSINTRs left?
90 if (sysIntr >= SYSINTR_MAXIMUM) {
91 OALMSG(OAL_ERROR, (L"ERROR: OALIntrRequestSysIntr: "
92 L"No avaiable SYSINTR found\r\n"
93 ));
94 sysIntr = SYSINTR_UNDEFINED;
95 goto cleanUp;
96 }
97
98 // Make SYSINTR -> IRQ association.
99 g_oalSysIntr2Irq[sysIntr] = irq;
100
101 // Make IRQ -> SYSINTR association if required
102 if ((flags & OAL_INTR_DYNAMIC) != 0) goto cleanUp;
103 if (
104 g_oalIrq2SysIntr[irq] == SYSINTR_UNDEFINED ||
105 (flags & OAL_INTR_FORCE_STATIC) != 0
106 ) {
107 g_oalIrq2SysIntr[irq] = sysIntr;
108 }
109
110 cleanUp:
111 OALMSG(OAL_INTR&&OAL_FUNC, (
112 L"-OALIntrRequestSysIntr(sysIntr = %d)\r\n", sysIntr
113 ));
114 return sysIntr;
115 }
116
117 //------------------------------------------------------------------------------
118 // 释放系统中断
119 // Function: OALIntrReleaseSysIntr
120 //
121 // This function release given SYSINTR and remove static mapping if exists.
122 //
123 BOOL OALIntrReleaseSysIntr(UINT32 sysIntr)
124 {
125 BOOL rc = FALSE;
126 UINT32 irq;
127
128 OALMSG(OAL_INTR&&OAL_FUNC, (L"+OALIntrReleaseSysIntr(%d)\r\n", sysIntr));
129
130 // Is the SYSINTR already released?
131 if (g_oalSysIntr2Irq[sysIntr] == OAL_INTR_IRQ_UNDEFINED) goto cleanUp;
132
133 // Remove the SYSINTR -> IRQ mapping
134 irq = g_oalSysIntr2Irq[sysIntr];
135 g_oalSysIntr2Irq[sysIntr] = OAL_INTR_IRQ_UNDEFINED;
136
137 // If we're releasing the SYSINTR directly mapped in the IRQ mapping,
138 // remove the IRQ mapping also
139 if (g_oalIrq2SysIntr[irq] == sysIntr) {
140 g_oalIrq2SysIntr[irq] = SYSINTR_UNDEFINED;
141 }
142
143 cleanUp:
144 OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrReleaseSysIntr(rc = %d)\r\n", rc));
145 return rc;
146 }
147 以上代码均来自C:\WINCE500\PLATFORM\COMMON\SRC\COMMON\INTR\BASE\map.c
148
149 //------------------------------------------------------------------------------
再来看OALIntrEnableIrqs这个函数是怎么实现的
OALIntrEnableIrqs
1 //------------------------------------------------------------------------------
2 //
3 // Function: OALIntrEnableIrqs
4 //
5 BOOL OALIntrEnableIrqs(UINT32 count, const UINT32 *pIrqs)
6 {
7 BOOL rc = TRUE;
8 UINT32 i, mask, irq;
9
10 OALMSG(OAL_INTR&&OAL_FUNC, (
11 L"+OALIntrEnableIrqs(%d, 0x%08x)\r\n", count, pIrqs
12 ));
13
14 for (i = 0; i < count; i++) {
15 #ifndef OAL_BSP_CALLBACKS
16 irq = pIrqs[i];
17 #else
18 // Give BSP chance to enable irq on subordinate interrupt controller
19 irq = BSPIntrEnableIrq(pIrqs[i]);
20 #endif
21 if (irq == OAL_INTR_IRQ_UNDEFINED) continue;
22 // Depending on IRQ number use internal or external mask register
23 if (irq <= IRQ_ADC) {
24 // Use interrupt mask register
25 CLRREG32(&g_pIntrRegs->INTMSK, 1 << irq);
26 } else if (irq <= IRQ_EINT7) {
27 // Use external mask register
28 CLRREG32(&g_pIntrRegs->INTMSK, 1 << IRQ_EINT4_7);
29 CLRREG32(&g_pPortRegs->EINTMASK, 1 << (irq - IRQ_EINT4 + 4));
30 } else if (irq <= IRQ_EINT23) {
31 // Use external mask register
32 mask = 1 << (irq - IRQ_EINT4 + 4);
33 OUTREG32(&g_pPortRegs->EINTPEND, mask);
34 CLRREG32(&g_pPortRegs->EINTMASK, mask);
35 mask = 1 << IRQ_EINT8_23;
36 if ((INREG32(&g_pIntrRegs->INTPND) & mask) != 0) {
37 OUTREG32(&g_pIntrRegs->INTPND, mask);
38 }
39 CLRREG32( &g_pIntrRegs->INTMSK, 1 << IRQ_EINT8_23);
40 } else {
41 rc = FALSE;
42 }
43 }
44
45 OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrEnableIrqs(rc = %d)\r\n", rc));
46 return rc;
47 }
通过以上的分析,这个代码是比较明朗,但是我们还是不明白这个中断到底是如何申请的,现在找一些驱动的代码来看看,以简单的重启按键驱动为例子,发现这个InterruptInitialize函数起到初始化中断和绑定线程的作用,现在看看PB帮助。
This function initializes a hardware interrupt with the kernel. This initialization allows the device driver to register an event and enable the interrupt.
BOOL InterruptInitialize( DWORD idInt,HANDLE hEvent,LPVOID pvData,DWORD cbData );
Parameters
Return Values
TRUE indicates success; FALSE indicates failure.
Remarks
This function must be called before using the hEvent parameter, which provides a link between the idInt parameter and the SYSINTR value returned by an ISR.
The hEvent parameter can only be used in a WaitForSingleObject call to wait for the event to be triggered by the kernel.
A WaitForMultipleObjects call with hEvent will fail.
If you use hEvent in a call to WaitForSingleObject before you call InterruptInitialize, InterruptInitialize will fail.
Requirements
OS Versions: Windows CE 2.10 and later.
Header: Pkfuncs.h.
Link Library: Coredll.lib.——郁闷,不开源的。
从PB帮助可以知道,这个
This function initializes a hardware interrupt with the kernel. This initialization allows the device driver to register an event and enable the interrupt.
BOOL InterruptInitialize( DWORD idInt,HANDLE hEvent,LPVOID pvData,DWORD cbData );
Parameters
Return Values
TRUE indicates success; FALSE indicates failure.
Remarks
This function must be called before using the hEvent parameter, which provides a link between the idInt parameter and the SYSINTR value returned by an ISR.
The hEvent parameter can only be used in a WaitForSingleObject call to wait for the event to be triggered by the kernel.
A WaitForMultipleObjects call with hEvent will fail.
If you use hEvent in a call to WaitForSingleObject before you call InterruptInitialize, InterruptInitialize will fail.
Requirements
OS Versions: Windows CE 2.10 and later.
Header: Pkfuncs.h.
Link Library: Coredll.lib.——郁闷,不开源的。
从PB帮助可以知道InterruptInitialize函数的功能是绑定线程和系统中断,并且调用OEMInterruptEnable使能中断
(When a device driver calls the InterruptInitialize kernel routine, the kernel then calls OEMInterruptEnable)
InterruptInitialize 函数使用的是系统中断来绑定线程的,那么这个物理中断是如何转换成系统中断的呢?这个5.0和4.2BSP是不同的。——答案是伟大的KernelIoControl函数,这个函数的具体用法请参照PB帮助吧。
This function provides the kernel with a generic I/O control for carrying out I/O operations.
BOOL KernelIoControl( DWORD dwIoControlCode,LPVOID lpInBuf,DWORD nInBufSize,LPVOID lpOutBuf,DWORD nOutBufSize,LPDWORD lpBytesReturned );
Parameters
Set to NULL if the dwIoControlCode parameter specifies an operation that does not require input data.
Set to NULL if the dwIoControlCode parameter specifies an operation that does not produce output data.
Return Values
TRUE indicates success; FALSE indicates failure.
Remarks
The kernel calls the OEMIoControl function when a device driver or application calls the kernel function KernelIoControl and passes an I/O control code. ——这个很关键,关于OEMIoControl 函数我在CSDN博客有介绍。这是实现中断转换的关键函数
This function is also called when the SystemParametersInfo function is called with SPI_GETOEMINFO or SPI_GETPLATFORMINFO.
The system is fully preemptible when this function is called. The kernel does no processing, but it passes all parameters directly to the function supplied by you.
This function is provided solely to allow your device driver or application to communicate with an OAL and its specific functionality.
现在就拿2440 5.0BSP串口驱动来具体分析一下
2440串口驱动
1 virtual BOOL Init() {
2 PHYSICAL_ADDRESS ioPhysicalBase = { S3C2440A_BASE_REG_PA_IOPORT, 0};
3 ULONG inIoSpace = 0;
4 if (TranslateBusAddr(m_hParent,Internal,0, ioPhysicalBase,&inIoSpace,&ioPhysicalBase)) {
5 // Map it if it is Memeory Mapped IO.
6 m_pIOPregs = (S3C2440A_IOPORT_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(S3C2440A_IOPORT_REG),FALSE);
7 }
8 if (m_pIOPregs) {
9 DDKISRINFO ddi;
10 //读取注册表的IRQ的键值(这个键值还是物理中断的值,是中断偏移寄存器(INTOFFSET指定IRQ中断源)的值,4.2BSP就利用了这个东西)
11 if (GetIsrInfo(&ddi)== ERROR_SUCCESS &&
12 KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &ddi.dwIrq, sizeof(UINT32), &ddi.dwSysintr, sizeof(UINT32), NULL))
13 { //使用KernelIoControl完成物理中断和系统中断转换之后,又把这个系统中断写入到注册表中,下次读出的中断
14 //就是系统中断了这样就完成了物理中断和系统中断之间的转换,比4.2BSP的方法聪明多了。
15 RegSetValueEx(DEVLOAD_SYSINTR_VALNAME,REG_DWORD,(PBYTE)&ddi.dwSysintr, sizeof(UINT32));
16 }
17 else
18 return FALSE;
19 m_pDTRPort = (volatile ULONG *)&(m_pIOPregs->GPDDAT);
20 m_pDSRPort = (volatile ULONG *)&(m_pIOPregs->GPDDAT);
21 m_dwDTRPortNum = 0;
22 m_dwDSRPortNum = 1;
23
24 m_pIOPregs->GPHCON &= ~(0x3<<0 | 0x3<<2 | 0x3<<4 | 0x3<<6 );//tx,rx,rts,cts
25 m_pIOPregs->GPHCON |= (0x2<<0 | 0x2<<2 | 0x2<<4 | 0x2<<6 );
26 m_pIOPregs->GPHCON |= (0x2<<0 | 0x2<<2);
27 m_pIOPregs->GPHUP |= 0xf;
28
29 m_pIOPregs->GPDCON &= ~(0x3<<0 | 0x3<<2);//dtr,dsr
30 m_pIOPregs->GPDCON |= (0x1<<0 | 0x0<<2);
31 m_pIOPregs->GPDUP |= 0x3;
32
33 return CPdd2440Uart::Init();//这里有大量的读注册表的操作,读出的中断是被上面修改过的系统中断了
34 }
35 return FALSE;
36 };
37
38 //---------------------------- 来看看这个再次读注册表的情况吧---------------------
39 BOOL CPdd2440Uart::Init()
40 {
41 if ( CSerialPDD::Init() && IsKeyOpened() && m_XmitFlushDone!=NULL) {
42 // IST Setup .--------Get IRQ forom regedit
43 DDKISRINFO ddi;
44 //再次读出注册表的中断,已经是系统中断了。
45 if (GetIsrInfo(&ddi)!=ERROR_SUCCESS) {
46 return FALSE;
47 }
48 m_dwSysIntr = ddi.dwSysintr;
49 if (m_dwSysIntr != MAXDWORD && m_dwSysIntr!=0 )
50 m_hISTEvent= CreateEvent(0,FALSE,FALSE,NULL);//创建事件,线程创建在后
51
52 //绑定中断PDD线程 ,和MDD中的线程有什么区别?
53 //ThreadRun
54 if (m_hISTEvent!=NULL)
55 InterruptInitialize(m_dwSysIntr,m_hISTEvent,0,0);
56 else
57 return FALSE;
58
59 // Get Device Index.
60 if (!GetRegValue(PC_REG_DEVINDEX_VAL_NAME, (PBYTE)&m_dwDevIndex, PC_REG_DEVINDEX_VAL_LEN)) {
61 m_dwDevIndex = 0;
62 }
63 if (!GetRegValue(PC_REG_SERIALWATERMARK_VAL_NAME,(PBYTE)&m_dwWaterMark,sizeof(DWORD))) {
64 m_dwWaterMark = 8;
65 }
66 if (!GetRegValue(PC_REG_2440UART_INTBIT_VAL_NAME,(PBYTE)&m_dwIntShift,sizeof(DWORD))) {
67 RETAILMSG(1,(TEXT("Registery does not have %s set. Drivers fail!!!\r\n"),PC_REG_2440UART_INTBIT_VAL_NAME));
68 m_dwIntShift =0;
69 return FALSE;
70 }
71 if (!GetRegValue(PC_REG_2440UART_IST_TIMEOUTS_VAL_NAME,(PBYTE)&m_dwISTTimeout, PC_REG_2440UART_IST_TIMEOUTS_VAL_LEN)) {
72 m_dwISTTimeout = INFINITE;
73 }
74 if (!MapHardware() || !CreateHardwareAccess()) {
75 return FALSE;
76 }
77
78 return TRUE;
79 }
80 return FALSE;
81 }
82
83
84
根据我以前在CSDN写的博客,这个KernelIoControl是通过IOCTL_HAL_REQUEST_SYSINTR达到目的,在File: oal_ioctl_tab.h有
{ IOCTL_HAL_REQUEST_SYSINTR, 0, OALIoCtlHalRequestSysIntr },
这个OALIoCtlHalRequestSysIntr正是前面实现物理中断和系统中断转换的函数。
OK,大功告成了!