Enable/Disable the irq in KeConnectInterrupt/KeDisconnectInterrupt.
[reactos.git] / reactos / ntoskrnl / ke / i386 / irq.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: irq.c,v 1.26 2002/12/09 19:53:44 hbirr Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ke/i386/irq.c
23 * PURPOSE: IRQ handling
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * UPDATE HISTORY:
26 * 29/05/98: Created
27 */
28
29 /*
30 * NOTE: In general the PIC interrupt priority facilities are used to
31 * preserve the NT IRQL semantics, global interrupt disables are only used
32 * to keep the PIC in a consistent state
33 *
34 */
35
36 /* INCLUDES ****************************************************************/
37
38 #include <ddk/ntddk.h>
39 #include <roscfg.h>
40 #include <internal/ke.h>
41 #include <internal/ps.h>
42 #include <internal/i386/segment.h>
43 #include <internal/pool.h>
44
45 #ifdef MP
46 #include <internal/hal/mps.h>
47 #endif /* MP */
48
49 #define NDEBUG
50 #include <internal/debug.h>
51
52 /* GLOBALS *****************************************************************/
53
54 #ifdef MP
55
56 /*
57 * FIXME: This does not work if we have more than 24 IRQs (ie. more than one
58 * I/O APIC)
59 */
60 #define VECTOR2IRQ(vector) (((vector) - 0x31) / 8)
61 #define VECTOR2IRQL(vector) (4 + VECTOR2IRQ(vector))
62
63 #define IRQ_BASE FIRST_DEVICE_VECTOR
64 #define NR_IRQS 0x100 - 0x30
65
66 #define __STR(x) #x
67 #define STR(x) __STR(x)
68
69 #define INT_NAME(intnum) _KiUnexpectedInterrupt##intnum
70 #define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
71
72 #define BUILD_COMMON_INTERRUPT_HANDLER() \
73 __asm__( \
74 "_KiCommonInterrupt:\n\t" \
75 "cld\n\t" \
76 "pushl %ds\n\t" \
77 "pushl %es\n\t" \
78 "pushl %fs\n\t" \
79 "pushl %gs\n\t" \
80 "movl $0xceafbeef,%eax\n\t" \
81 "pushl %eax\n\t" \
82 "movl $" STR(KERNEL_DS) ",%eax\n\t" \
83 "movl %eax,%ds\n\t" \
84 "movl %eax,%es\n\t" \
85 "movl $" STR(PCR_SELECTOR) ",%eax\n\t" \
86 "movl %eax,%fs\n\t" \
87 "pushl %esp\n\t" \
88 "pushl %ebx\n\t" \
89 "call _KiInterruptDispatch\n\t" \
90 "popl %eax\n\t" \
91 "popl %eax\n\t" \
92 "popl %eax\n\t" \
93 "popl %gs\n\t" \
94 "popl %fs\n\t" \
95 "popl %es\n\t" \
96 "popl %ds\n\t" \
97 "popa\n\t" \
98 "iret\n\t");
99
100 #define BUILD_INTERRUPT_HANDLER(intnum) \
101 VOID INT_NAME2(intnum)(VOID); \
102 __asm__( \
103 STR(INT_NAME(intnum)) ":\n\t" \
104 "pusha\n\t" \
105 "movl $0x" STR(intnum) ",%ebx\n\t" \
106 "jmp _KiCommonInterrupt");
107
108
109 /* Interrupt handlers and declarations */
110
111 #define B(x,y) \
112 BUILD_INTERRUPT_HANDLER(x##y)
113
114 #define B16(x) \
115 B(x,0) B(x,1) B(x,2) B(x,3) \
116 B(x,4) B(x,5) B(x,6) B(x,7) \
117 B(x,8) B(x,9) B(x,A) B(x,B) \
118 B(x,C) B(x,D) B(x,E) B(x,F)
119
120
121 BUILD_COMMON_INTERRUPT_HANDLER()
122 B16(3) B16(4) B16(5) B16(6)
123 B16(7) B16(8) B16(9) B16(A)
124 B16(B) B16(C) B16(D) B16(E)
125 B16(F)
126
127 #undef B
128 #undef B16
129
130
131 /* Interrupt handler list */
132
133 #define L(x,y) \
134 (ULONG)& INT_NAME2(x##y)
135
136 #define L16(x) \
137 L(x,0), L(x,1), L(x,2), L(x,3), \
138 L(x,4), L(x,5), L(x,6), L(x,7), \
139 L(x,8), L(x,9), L(x,A), L(x,B), \
140 L(x,C), L(x,D), L(x,E), L(x,F)
141
142 static ULONG irq_handler[NR_IRQS] = {
143 L16(3), L16(4), L16(5), L16(6),
144 L16(7), L16(8), L16(9), L16(A),
145 L16(B), L16(C), L16(D), L16(E),
146 L16(F)
147 };
148
149 #undef L
150 #undef L16
151
152 #else /* MP */
153
154 #define NR_IRQS (16)
155 #define IRQ_BASE (0x40)
156
157 void irq_handler_0(void);
158 void irq_handler_1(void);
159 void irq_handler_2(void);
160 void irq_handler_3(void);
161 void irq_handler_4(void);
162 void irq_handler_5(void);
163 void irq_handler_6(void);
164 void irq_handler_7(void);
165 void irq_handler_8(void);
166 void irq_handler_9(void);
167 void irq_handler_10(void);
168 void irq_handler_11(void);
169 void irq_handler_12(void);
170 void irq_handler_13(void);
171 void irq_handler_14(void);
172 void irq_handler_15(void);
173
174 static unsigned int irq_handler[NR_IRQS]=
175 {
176 (int)&irq_handler_0,
177 (int)&irq_handler_1,
178 (int)&irq_handler_2,
179 (int)&irq_handler_3,
180 (int)&irq_handler_4,
181 (int)&irq_handler_5,
182 (int)&irq_handler_6,
183 (int)&irq_handler_7,
184 (int)&irq_handler_8,
185 (int)&irq_handler_9,
186 (int)&irq_handler_10,
187 (int)&irq_handler_11,
188 (int)&irq_handler_12,
189 (int)&irq_handler_13,
190 (int)&irq_handler_14,
191 (int)&irq_handler_15,
192 };
193
194 #endif /* MP */
195
196 /*
197 * PURPOSE: Object describing each isr
198 * NOTE: The data in this table is only modified at passsive level but can
199 * be accessed at any irq level.
200 */
201
202 static LIST_ENTRY isr_table[NR_IRQS]={{NULL,NULL},};
203 static PKSPIN_LOCK isr_lock[NR_IRQS] = {NULL,};
204 static KSPIN_LOCK isr_table_lock = {0,};
205
206 #define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
207 #define TAG_KINTERRUPT TAG('K', 'I', 'S', 'R')
208
209 /* FUNCTIONS ****************************************************************/
210
211 #define PRESENT (0x8000)
212 #define I486_INTERRUPT_GATE (0xe00)
213
214 VOID KeInitInterrupts (VOID)
215 {
216 int i;
217
218 #ifdef MP
219
220 /*
221 * Setup the IDT entries to point to the interrupt handlers
222 */
223 for (i=0;i<NR_IRQS;i++)
224 {
225 KiIdt[0x30+i].a=(irq_handler[i]&0xffff)+(KERNEL_CS<<16);
226 KiIdt[0x30+i].b=(irq_handler[i]&0xffff0000)+PRESENT+
227 I486_INTERRUPT_GATE;
228 InitializeListHead(&isr_table[i]);
229 }
230
231 #else
232
233 /*
234 * Setup the IDT entries to point to the interrupt handlers
235 */
236 for (i=0;i<NR_IRQS;i++)
237 {
238 KiIdt[IRQ_BASE+i].a=(irq_handler[i]&0xffff)+(KERNEL_CS<<16);
239 KiIdt[IRQ_BASE+i].b=(irq_handler[i]&0xffff0000)+PRESENT+
240 I486_INTERRUPT_GATE;
241 InitializeListHead(&isr_table[i]);
242 }
243
244 #endif
245
246 }
247
248 typedef struct _KIRQ_TRAPFRAME
249 {
250 ULONG Magic;
251 ULONG Fs;
252 ULONG Es;
253 ULONG Ds;
254 ULONG Eax;
255 ULONG Ecx;
256 ULONG Edx;
257 ULONG Ebx;
258 ULONG Esp;
259 ULONG Ebp;
260 ULONG Esi;
261 ULONG Edi;
262 ULONG Eip;
263 ULONG Cs;
264 ULONG Eflags;
265 } KIRQ_TRAPFRAME, *PKIRQ_TRAPFRAME;
266
267 #ifdef DBG
268
269 VOID
270 KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
271 PKTRAP_FRAME TrapFrame)
272 {
273 TrapFrame->Fs = IrqTrapFrame->Fs;
274 TrapFrame->Fs = IrqTrapFrame->Es;
275 TrapFrame->Ds = IrqTrapFrame->Ds;
276 TrapFrame->Eax = IrqTrapFrame->Eax;
277 TrapFrame->Ecx = IrqTrapFrame->Ecx;
278 TrapFrame->Edx = IrqTrapFrame->Edx;
279 TrapFrame->Ebx = IrqTrapFrame->Ebx;
280 TrapFrame->Esp = IrqTrapFrame->Esp;
281 TrapFrame->Ebp = IrqTrapFrame->Ebp;
282 TrapFrame->Esi = IrqTrapFrame->Esi;
283 TrapFrame->Edi = IrqTrapFrame->Edi;
284 TrapFrame->Eip = IrqTrapFrame->Eip;
285 TrapFrame->Cs = IrqTrapFrame->Cs;
286 TrapFrame->Eflags = IrqTrapFrame->Eflags;
287 }
288
289 #endif
290
291 #ifdef MP
292
293 VOID STDCALL
294 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level)
295 /*
296 * FUNCTION: Calls all the interrupt handlers for a given irq.
297 * ARGUMENTS:
298 * Irq - The number of the irq to call handlers for.
299 * old_level - The irql of the processor when the irq took place.
300 * NOTES: Must be called at DIRQL.
301 */
302 {
303 PKINTERRUPT isr;
304 PLIST_ENTRY current;
305
306 DPRINT("\nWARNING - KiInterruptDispatch2 copied directly from UP version for build\npurposes only, please review\n\n");
307
308 if (Irq == 0)
309 {
310 KiUpdateSystemTime(old_level, 0);
311 }
312 else
313 {
314 /*
315 * Iterate the list until one of the isr tells us its device interrupted
316 */
317 current = isr_table[Irq].Flink;
318 isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
319 while (current != &isr_table[Irq] &&
320 !isr->ServiceRoutine(isr, isr->ServiceContext))
321 {
322 current = current->Flink;
323 isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
324 }
325 }
326 }
327
328 VOID
329 KiInterruptDispatch (ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
330 /*
331 * FUNCTION: Calls the irq specific handler for an irq
332 * ARGUMENTS:
333 * Vector = Interrupt vector
334 * Trapframe = CPU context
335 */
336 {
337 KIRQL old_level;
338 PKINTERRUPT isr;
339 PLIST_ENTRY current;
340 ULONG irq;
341
342 #ifdef DBG
343
344 KTRAP_FRAME KernelTrapFrame;
345
346 KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
347 KeGetCurrentThread()->TrapFrame = &KernelTrapFrame;
348
349 #endif /* DBG */
350
351 DPRINT("I(%d) ", Vector);
352
353 /*
354 * Notify the rest of the kernel of the raised irq level
355 */
356 HalBeginSystemInterrupt (Vector,
357 VECTOR2IRQL(Vector),
358 &old_level);
359
360 irq = VECTOR2IRQ(Vector);
361
362 /*
363 * Enable interrupts
364 * NOTE: Only higher priority interrupts will get through
365 */
366 __asm__("sti\n\t");
367
368 if (irq == 0)
369 {
370 if (KeGetCurrentProcessorNumber() == 0)
371 {
372 KiUpdateSystemTime(old_level, Trapframe->Eip);
373 }
374 }
375 else
376 {
377 DPRINT("KiInterruptDispatch(Vector %d)\n", Vector);
378 /*
379 * Iterate the list until one of the isr tells us its device interrupted
380 */
381 current = isr_table[irq].Flink;
382 isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
383 //DPRINT("current %x isr %x\n",current,isr);
384 while (current!=(&isr_table[irq]) &&
385 !isr->ServiceRoutine(isr,isr->ServiceContext))
386 {
387 current = current->Flink;
388 isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
389 //DPRINT("current %x isr %x\n",current,isr);
390 }
391 }
392 /*
393 * Disable interrupts
394 */
395 __asm__("cli\n\t");
396
397 /*
398 * Unmask the related irq
399 */
400 HalEnableSystemInterrupt (Vector, 0, 0);
401
402 /*
403 * If the processor level will drop below dispatch level on return then
404 * issue a DPC queue drain interrupt
405 */
406
407 __asm__("sti\n\t");
408
409 if (old_level < DISPATCH_LEVEL)
410 {
411
412 HalEndSystemInterrupt (DISPATCH_LEVEL, 0);
413
414 if (KeGetCurrentThread() != NULL)
415 {
416 // FIXME TODO - What happend to LastEip definition?
417 //KeGetCurrentThread()->LastEip = Trapframe->Eip;
418 }
419 KiDispatchInterrupt();
420 if (KeGetCurrentThread() != NULL &&
421 KeGetCurrentThread()->Alerted[1] != 0 &&
422 Trapframe->Cs != KERNEL_CS)
423 {
424 HalEndSystemInterrupt (APC_LEVEL, 0);
425 KiDeliverNormalApc();
426 }
427 }
428
429 HalEndSystemInterrupt (old_level, 0);
430 }
431
432 #else /* MP */
433
434 VOID STDCALL
435 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level)
436 /*
437 * FUNCTION: Calls all the interrupt handlers for a given irq.
438 * ARGUMENTS:
439 * Irq - The number of the irq to call handlers for.
440 * old_level - The irql of the processor when the irq took place.
441 * NOTES: Must be called at DIRQL.
442 */
443 {
444 PKINTERRUPT isr;
445 PLIST_ENTRY current;
446
447 if (Irq == 0)
448 {
449 KiUpdateSystemTime(old_level, 0);
450 }
451 else
452 {
453 /*
454 * Iterate the list until one of the isr tells us its device interrupted
455 */
456 current = isr_table[Irq].Flink;
457 while (current != &isr_table[Irq])
458 {
459 isr = CONTAINING_RECORD(current,KINTERRUPT,Entry);
460 #if 0
461 if (isr->ServiceRoutine(isr, isr->ServiceContext))
462 {
463 break;
464 }
465 #else
466 isr->ServiceRoutine(isr, isr->ServiceContext);
467 #endif
468 current = current->Flink;
469 }
470 }
471 }
472
473 VOID
474 KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe)
475 /*
476 * FUNCTION: Calls the irq specific handler for an irq
477 * ARGUMENTS:
478 * irq = IRQ that has interrupted
479 */
480 {
481 KIRQL old_level;
482
483 /*
484 * At this point we have interrupts disabled, nothing has been done to
485 * the PIC.
486 */
487
488 /*
489 * Notify the rest of the kernel of the raised irq level. For the
490 * default HAL this will send an EOI to the PIC and alter the IRQL.
491 */
492 if (!HalBeginSystemInterrupt (irq + IRQ_BASE,
493 PROFILE_LEVEL - irq,
494 &old_level))
495 {
496 return;
497 }
498
499 /*
500 * Enable interrupts
501 * NOTE: Only higher priority interrupts will get through
502 */
503 __asm__("sti\n\t");
504
505 /*
506 * Actually call the ISR.
507 */
508 KiInterruptDispatch2(irq, old_level);
509
510 /*
511 * End the system interrupt.
512 */
513 HalEndSystemInterrupt (old_level, 0);
514
515 /*
516 * Maybe do a reschedule as well.
517 */
518 if (old_level < DISPATCH_LEVEL && irq == 0)
519 {
520 PsDispatchThread(THREAD_STATE_READY);
521 }
522 }
523
524 #endif /* MP */
525
526 static VOID
527 KeDumpIrqList(VOID)
528 {
529 PKINTERRUPT current;
530 PLIST_ENTRY current_entry;
531 unsigned int i;
532
533 for (i=0;i<NR_IRQS;i++)
534 {
535 DPRINT("For irq %x ",i);
536 current_entry = isr_table[i].Flink;
537 current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry);
538 while (current_entry!=(&isr_table[i]))
539 {
540 DPRINT("Isr %x ",current);
541 current_entry = current_entry->Flink;
542 current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry);
543 }
544 DPRINT("\n",0);
545 }
546 }
547
548 NTSTATUS STDCALL
549 KeConnectInterrupt(PKINTERRUPT InterruptObject)
550 {
551 KIRQL oldlvl;
552 KIRQL synch_oldlvl;
553 PKINTERRUPT ListHead;
554 ULONG Vector;
555
556 DPRINT("KeConnectInterrupt()\n");
557
558 Vector = InterruptObject->Vector;
559
560 /*
561 * Acquire the table spinlock
562 */
563 KeAcquireSpinLock(&isr_table_lock,&oldlvl);
564
565 /*
566 * Check if the vector is already in use that we can share it
567 */
568 ListHead = CONTAINING_RECORD(isr_table[Vector].Flink,KINTERRUPT,Entry);
569 if (!IsListEmpty(&isr_table[Vector]) &&
570 (InterruptObject->Shareable == FALSE || ListHead->Shareable==FALSE))
571 {
572 KeReleaseSpinLock(&isr_table_lock,oldlvl);
573 return(STATUS_INVALID_PARAMETER);
574 }
575 else
576 {
577 isr_lock[Vector] =
578 ExAllocatePoolWithTag(NonPagedPool, sizeof(KSPIN_LOCK),
579 TAG_ISR_LOCK);
580 KeInitializeSpinLock(isr_lock[Vector]);
581 }
582
583 InterruptObject->IrqLock = isr_lock[Vector];
584
585 KeRaiseIrql(InterruptObject->SynchLevel,&synch_oldlvl);
586 KeAcquireSpinLockAtDpcLevel(InterruptObject->IrqLock);
587 DPRINT("%x %x\n",isr_table[Vector].Flink,isr_table[Vector].Blink);
588 if (IsListEmpty(&isr_table[Vector]))
589 {
590 HalEnableSystemInterrupt(Vector + IRQ_BASE, 0, 0);
591 }
592 InsertTailList(&isr_table[Vector],&InterruptObject->Entry);
593 DPRINT("%x %x\n",InterruptObject->Entry.Flink,
594 InterruptObject->Entry.Blink);
595 KeReleaseSpinLockFromDpcLevel(InterruptObject->IrqLock);
596 KeLowerIrql(synch_oldlvl);
597
598 /*
599 * Release the table spinlock
600 */
601 KeReleaseSpinLock(&isr_table_lock,oldlvl);
602
603 KeDumpIrqList();
604
605 return STATUS_SUCCESS;
606 }
607
608
609 VOID STDCALL
610 KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
611 /*
612 * FUNCTION: Releases a drivers isr
613 * ARGUMENTS:
614 * InterruptObject = isr to release
615 */
616 {
617 KIRQL oldlvl;
618
619 KeRaiseIrql(InterruptObject->SynchLevel,&oldlvl);
620 KeAcquireSpinLockAtDpcLevel(InterruptObject->IrqLock);
621 RemoveEntryList(&InterruptObject->Entry);
622 if (IsListEmpty(&isr_table[InterruptObject->Vector]))
623 {
624 HalDisableSystemInterrupt(InterruptObject->Vector + IRQ_BASE, 0);
625 }
626 KeReleaseSpinLockFromDpcLevel(InterruptObject->IrqLock);
627 KeLowerIrql(oldlvl);
628 }
629
630
631 NTSTATUS
632 STDCALL
633 KeInitializeInterrupt(PKINTERRUPT InterruptObject,
634 PKSERVICE_ROUTINE ServiceRoutine,
635 PVOID ServiceContext,
636 PKSPIN_LOCK SpinLock,
637 ULONG Vector,
638 KIRQL Irql,
639 KIRQL SynchronizeIrql,
640 KINTERRUPT_MODE InterruptMode,
641 BOOLEAN ShareVector,
642 KAFFINITY ProcessorEnableMask,
643 BOOLEAN FloatingSave)
644 {
645 InterruptObject->ServiceContext = ServiceContext;
646 InterruptObject->ServiceRoutine = ServiceRoutine;
647 InterruptObject->Vector = Vector;
648 InterruptObject->ProcessorEnableMask = ProcessorEnableMask;
649 InterruptObject->SynchLevel = SynchronizeIrql;
650 InterruptObject->Shareable = ShareVector;
651 InterruptObject->FloatingSave = FALSE;
652
653 return STATUS_SUCCESS;
654 }
655
656
657 NTSTATUS STDCALL
658 IoConnectInterrupt(PKINTERRUPT* InterruptObject,
659 PKSERVICE_ROUTINE ServiceRoutine,
660 PVOID ServiceContext,
661 PKSPIN_LOCK SpinLock,
662 ULONG Vector,
663 KIRQL Irql,
664 KIRQL SynchronizeIrql,
665 KINTERRUPT_MODE InterruptMode,
666 BOOLEAN ShareVector,
667 KAFFINITY ProcessorEnableMask,
668 BOOLEAN FloatingSave)
669 /*
670 * FUNCTION: Registers a driver's isr to be called when its device interrupts
671 * ARGUMENTS:
672 * InterruptObject (OUT) = Points to the interrupt object created on
673 * return
674 * ServiceRoutine = Routine to be called when the device interrupts
675 * ServiceContext = Parameter to be passed to ServiceRoutine
676 * SpinLock = Initalized spinlock that will be used to synchronize
677 * access between the isr and other driver routines. This is
678 * required if the isr handles more than one vector or the
679 * driver has more than one isr
680 * Vector = Interrupt vector to allocate
681 * (returned from HalGetInterruptVector)
682 * Irql = DIRQL returned from HalGetInterruptVector
683 * SynchronizeIrql = DIRQL at which the isr will execute. This must
684 * be the highest of all the DIRQLs returned from
685 * HalGetInterruptVector if the driver has multiple
686 * isrs
687 * InterruptMode = Specifies if the interrupt is LevelSensitive or
688 * Latched
689 * ShareVector = Specifies if the vector can be shared
690 * ProcessorEnableMask = Processors on the isr can run
691 * FloatingSave = TRUE if the floating point stack should be saved when
692 * the isr runs. Must be false for x86 drivers
693 * RETURNS: Status
694 * IRQL: PASSIVE_LEVEL
695 */
696 {
697 PKINTERRUPT Interrupt;
698 NTSTATUS Status = STATUS_SUCCESS;
699
700 ASSERT_IRQL(PASSIVE_LEVEL);
701
702 DPRINT("IoConnectInterrupt(Vector %x)\n",Vector);
703
704 /*
705 * Check the parameters
706 */
707 if (Vector >= NR_IRQS)
708 {
709 return(STATUS_INVALID_PARAMETER);
710 }
711 if (FloatingSave == TRUE)
712 {
713 return(STATUS_INVALID_PARAMETER);
714 }
715
716 /*
717 * Initialize interrupt object
718 */
719 Interrupt=ExAllocatePoolWithTag(NonPagedPool,sizeof(KINTERRUPT),
720 TAG_KINTERRUPT);
721 if (Interrupt==NULL)
722 {
723 return(STATUS_INSUFFICIENT_RESOURCES);
724 }
725
726 Status = KeInitializeInterrupt(Interrupt,
727 ServiceRoutine,
728 ServiceContext,
729 SpinLock,
730 Vector,
731 Irql,
732 SynchronizeIrql,
733 InterruptMode,
734 ShareVector,
735 ProcessorEnableMask,
736 FloatingSave);
737 if (!NT_SUCCESS(Status))
738 {
739 ExFreePool(Interrupt);
740 return Status;
741 }
742
743 Status = KeConnectInterrupt(Interrupt);
744 if (!NT_SUCCESS(Status))
745 {
746 ExFreePool(Interrupt);
747 return Status;
748 }
749
750 *InterruptObject = Interrupt;
751
752 return(STATUS_SUCCESS);
753 }
754
755
756 VOID STDCALL
757 IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
758 /*
759 * FUNCTION: Releases a drivers isr
760 * ARGUMENTS:
761 * InterruptObject = isr to release
762 */
763 {
764 KeDisconnectInterrupt(InterruptObject);
765 ExFreePool(InterruptObject);
766 }
767
768 /* EOF */