2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: mkernel/hal/x86/irq.c
5 * PURPOSE: IRQ handling
6 * PROGRAMMER: David Welch (welch@mcmail.com)
12 * NOTE: In general the PIC interrupt priority facilities are used to
13 * preserve the NT IRQL semantics, global interrupt disables are only used
14 * to keep the PIC in a consistent state
18 /* INCLUDES ****************************************************************/
20 #include <ddk/ntddk.h>
22 #include <internal/stddef.h>
23 #include <internal/kernel.h>
24 #include <internal/bitops.h>
25 #include <internal/linkage.h>
26 #include <internal/string.h>
28 #include <internal/hal/segment.h>
29 #include <internal/hal/io.h>
32 #include <internal/debug.h>
34 /* GLOBALS *****************************************************************/
37 #define IRQ_BASE (0x20)
39 asmlinkage
void irq_handler_0(void);
40 asmlinkage
void irq_handler_1(void);
41 asmlinkage
void irq_handler_2(void);
42 asmlinkage
void irq_handler_3(void);
43 asmlinkage
void irq_handler_4(void);
44 asmlinkage
void irq_handler_5(void);
45 asmlinkage
void irq_handler_6(void);
46 asmlinkage
void irq_handler_7(void);
47 asmlinkage
void irq_handler_8(void);
48 asmlinkage
void irq_handler_9(void);
49 asmlinkage
void irq_handler_10(void);
50 asmlinkage
void irq_handler_11(void);
51 asmlinkage
void irq_handler_12(void);
52 asmlinkage
void irq_handler_13(void);
53 asmlinkage
void irq_handler_14(void);
54 asmlinkage
void irq_handler_15(void);
56 static unsigned int irq_handler
[NR_IRQS
]=
77 * PURPOSE: Object describing each isr
78 * NOTE: The data in this table is only modified at passsive level but can
79 * be accessed at any irq level.
81 static LIST_ENTRY isr_table
[NR_IRQS
]={{NULL
,NULL
},};
82 static PKSPIN_LOCK isr_lock
[NR_IRQS
];
83 static KSPIN_LOCK isr_table_lock
;
85 /* FUNCTIONS ****************************************************************/
88 #define PRESENT (0x8000)
89 #define I486_INTERRUPT_GATE (0xe00)
91 asmlinkage
void KiInterruptDispatch(unsigned int irq
)
93 * FUNCTION: Calls the irq specific handler for an irq
95 * irq = IRQ that has interrupted
103 * Notify the rest of the kernel of the raised irq level
105 old_level
= KeGetCurrentIrql();
106 DPRINT("old_level %d\n",old_level
);
107 KeSetCurrentIrql(HIGH_LEVEL
- irq
);
111 * NOTE: Only higher priority interrupts will get through
121 DPRINT("KiInterruptDispatch(irq %x)\n",irq
);
123 * Iterate the list until one of the isr tells us its device interrupted
125 current
= isr_table
[irq
].Flink
;
126 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
127 DPRINT("current %x isr %x\n",current
,isr
);
128 while (current
!=NULL
&& !isr
->ServiceRoutine(isr
,isr
->ServiceContext
))
130 current
= current
->Flink
;
131 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
132 DPRINT("current %x isr %x\n",current
,isr
);
142 * Send EOI to the PIC
151 * Unmask the related irq
155 outb(0x21,inb(0x21)&(~(1<<irq
)));
159 outb(0xa1,inb(0xa1)&(~(1<<(irq
-8))));
163 * If the processor level will drop below dispatch level on return then
164 * issue a DPC queue drain interrupt
166 if (old_level
< DISPATCH_LEVEL
)
168 KeSetCurrentIrql(DISPATCH_LEVEL
);
170 KiDispatchInterrupt(irq
);
172 KeSetCurrentIrql(old_level
);
175 void InitalizeIRQ(void)
180 * First mask off all interrupts from pic
187 * Setup the IDT entries to point to the interrupt handlers
189 for (i
=0;i
<NR_IRQS
;i
++)
191 idt
[IRQ_BASE
+i
].a
=(irq_handler
[i
]&0xffff)+(KERNEL_CS
<<16);
192 idt
[IRQ_BASE
+i
].b
=(irq_handler
[i
]&0xffff0000)+PRESENT
+
194 InitializeListHead(&isr_table
[i
]);
198 NTSTATUS
IoConnectInterrupt(PKINTERRUPT
* InterruptObject
,
199 PKSERVICE_ROUTINE ServiceRoutine
,
200 PVOID ServiceContext
,
201 PKSPIN_LOCK SpinLock
,
204 KIRQL SynchronizeIrql
,
205 KINTERRUPT_MODE InterruptMode
,
207 KAFFINITY ProcessorEnableMask
,
208 BOOLEAN FloatingSave
)
210 * FUNCTION: Registers a driver's isr to be called when its device interrupts
212 * InterruptObject (OUT) = Points to the interrupt object created on
214 * ServiceRoutine = Routine to be called when the device interrupts
215 * ServiceContext = Parameter to be passed to ServiceRoutine
216 * SpinLock = Initalized spinlock that will be used to synchronize
217 * access between the isr and other driver routines. This is
218 * required if the isr handles more than one vector or the
219 * driver has more than one isr
220 * Vector = Interrupt vector to allocate
221 * (returned from HalGetInterruptVector)
222 * Irql = DIRQL returned from HalGetInterruptVector
223 * SynchronizeIrql = DIRQL at which the isr will execute. This must
224 * be the highest of all the DIRQLs returned from
225 * HalGetInterruptVector if the driver has multiple
227 * InterruptMode = Specifies if the interrupt is LevelSensitive or
229 * ShareVector = Specifies if the vector can be shared
230 * ProcessorEnableMask = Processors on the isr can run
231 * FloatingSave = TRUE if the floating point stack should be saved when
232 * the isr runs. Must be false for x86 drivers
234 * IRQL: PASSIVE_LEVEL
239 PKINTERRUPT ListHead
;
241 ASSERT_IRQL(PASSIVE_LEVEL
);
244 * Check the parameters
246 if (Vector
>= NR_IRQS
)
248 return(STATUS_INVALID_PARAMETER
);
250 if (FloatingSave
== TRUE
)
252 return(STATUS_INVALID_PARAMETER
);
256 * Acquire the table spinlock
258 KeAcquireSpinLock(&isr_table_lock
,&oldlvl
);
261 * Check if the vector is already in use that we can share it
263 ListHead
= CONTAINING_RECORD(isr_table
[Vector
].Flink
,KINTERRUPT
,Entry
);
264 if (!IsListEmpty(&isr_table
[Vector
]) &&
265 (ShareVector
== FALSE
|| ListHead
->Shareable
==FALSE
))
267 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
268 return(STATUS_INVALID_PARAMETER
);
272 isr_lock
[Vector
]=ExAllocatePool(NonPagedPool
,sizeof(KSPIN_LOCK
));
273 KeInitializeSpinLock(isr_lock
[Vector
]);
274 isr_lock
[Vector
]->irql
= SynchronizeIrql
;
278 * Initialize interrupt object
280 (*InterruptObject
)=ExAllocatePool(NonPagedPool
,sizeof(KINTERRUPT
));
281 if ((*InterruptObject
)==NULL
)
283 return(STATUS_INSUFFICIENT_RESOURCES
);
285 (*InterruptObject
)->ServiceContext
= ServiceContext
;
286 (*InterruptObject
)->ServiceRoutine
= ServiceRoutine
;
287 (*InterruptObject
)->Vector
= Vector
;
288 (*InterruptObject
)->ProcessorEnableMask
= ProcessorEnableMask
;
289 (*InterruptObject
)->SynchLevel
= SynchronizeIrql
;
290 (*InterruptObject
)->Shareable
= ShareVector
;
291 (*InterruptObject
)->FloatingSave
= FALSE
;
292 (*InterruptObject
)->IrqLock
= isr_lock
[Vector
];
294 KeRaiseIrql((*InterruptObject
)->SynchLevel
,&synch_oldlvl
);
295 KeAcquireSpinLockAtDpcLevel((*InterruptObject
)->IrqLock
);
296 DPRINT("%x %x\n",isr_table
[Vector
].Flink
,isr_table
[Vector
].Blink
);
297 InsertTailList(&isr_table
[Vector
],&((*InterruptObject
)->Entry
));
298 DPRINT("%x %x\n",(*InterruptObject
)->Entry
.Flink
,
299 (*InterruptObject
)->Entry
.Blink
);
300 KeReleaseSpinLockFromDpcLevel((*InterruptObject
)->IrqLock
);
301 KeLowerIrql(synch_oldlvl
);
304 * Release the table spinlock
306 KeReleaseSpinLock(&isr_table_lock
,oldlvl
);
308 return(STATUS_SUCCESS
);
312 VOID
IoDisconnectInterrupt(PKINTERRUPT InterruptObject
)
314 * FUNCTION: Releases a drivers isr
316 * InterruptObject = isr to release
321 KeRaiseIrql(InterruptObject
->SynchLevel
,&oldlvl
);
322 KeAcquireSpinLockAtDpcLevel(InterruptObject
->IrqLock
);
323 RemoveEntryFromList(&isr_table
[InterruptObject
->Vector
],
324 &InterruptObject
->Entry
);
325 KeReleaseSpinLockFromDpcLevel(InterruptObject
->IrqLock
);
329 ULONG
HalGetInterruptVector(INTERFACE_TYPE InterfaceType
,
331 ULONG BusInterruptLevel
,
332 ULONG BusInterruptVector
,
336 * FUNCTION: Returns a mapped system interrupt vector for passing to
339 * InterfaceType = Type bus the device is on
340 * BusNumber = Zero based number of the bus
341 * BusInterruptLevel = Bus specific interrupt level
342 * BusInterruptVector = Bus specific interrupt vector
343 * Irql (IN/OUT) = On entry the bus relative IRQL
345 * Affinity (OUT) = Caller supplied storage for the interrupt
347 * RETURNS: The mapped vector
352 // ASSERT_IRQL(PASSIVE_LEVEL);
354 switch (InterfaceType
)
357 *Irql
= HIGH_LEVEL
- BusInterruptVector
;
358 ret
= BusInterruptVector
;
363 printk("(%s:%d) Don't know that bus type\n",__FILE__
,__LINE__
);