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