2 This contains the installation function for the driver.
4 Copyright (c) 2005 - 2009, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 // Global for the Legacy 8259 Protocol that is produced by this driver
20 EFI_LEGACY_8259_PROTOCOL mInterrupt8259
= {
21 Interrupt8259SetVectorBase
,
25 Interrupt8259GetVector
,
26 Interrupt8259EnableIrq
,
27 Interrupt8259DisableIrq
,
28 Interrupt8259GetInterruptLine
,
29 Interrupt8259EndOfInterrupt
33 // Global for the handle that the Legacy 8259 Protocol is installed
35 EFI_HANDLE m8259Handle
= NULL
;
37 UINT8 mMasterBase
= 0xff;
38 UINT8 mSlaveBase
= 0xff;
39 EFI_8259_MODE mMode
= Efi8259ProtectedMode
;
40 UINT16 mProtectedModeMask
= 0xffff;
41 UINT16 mLegacyModeMask
= FixedPcdGet16(Pcd8259LegacyModeMask
);
42 UINT16 mProtectedModeEdgeLevel
= 0x0000;
43 UINT16 mLegacyModeEdgeLevel
= FixedPcdGet16(Pcd8259LegacyModeEdgeLevel
);
50 Write to mask and edge/level triggered registers of master and slave PICs.
52 @param[in] Mask low byte for master PIC mask register,
53 high byte for slave PIC mask register.
54 @param[in] EdgeLevel low byte for master PIC edge/level triggered register,
55 high byte for slave PIC edge/level triggered register.
59 Interrupt8259WriteMask (
64 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, (UINT8
) Mask
);
65 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, (UINT8
) (Mask
>> 8));
66 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER
, (UINT8
) EdgeLevel
);
67 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE
, (UINT8
) (EdgeLevel
>> 8));
71 Read from mask and edge/level triggered registers of master and slave PICs.
73 @param[out] Mask low byte for master PIC mask register,
74 high byte for slave PIC mask register.
75 @param[out] EdgeLevel low byte for master PIC edge/level triggered register,
76 high byte for slave PIC edge/level triggered register.
80 Interrupt8259ReadMask (
89 MasterValue
= IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER
);
90 SlaveValue
= IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE
);
92 *Mask
= (UINT16
) (MasterValue
| (SlaveValue
<< 8));
95 if (EdgeLevel
!= NULL
) {
96 MasterValue
= IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER
);
97 SlaveValue
= IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE
);
99 *EdgeLevel
= (UINT16
) (MasterValue
| (SlaveValue
<< 8));
104 // Legacy 8259 Protocol Interface Functions
108 Sets the base address for the 8259 master and slave PICs.
110 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
111 @param[in] MasterBase Interrupt vectors for IRQ0-IRQ7.
112 @param[in] SlaveBase Interrupt vectors for IRQ8-IRQ15.
114 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
115 @retval EFI_DEVICE_ERROR There was an error while writing to the 8259 PIC.
120 Interrupt8259SetVectorBase (
121 IN EFI_LEGACY_8259_PROTOCOL
*This
,
129 // Set vector base for slave PIC
131 if (SlaveBase
!= mSlaveBase
) {
132 mSlaveBase
= SlaveBase
;
135 // Initialization sequence is needed for setting vector base.
139 // Preserve interrtup mask register before initialization sequence
140 // because it will be cleared during intialization
142 Mask
= IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE
);
145 // ICW1: cascade mode, ICW4 write required
147 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE
, 0x11);
150 // ICW2: new vector base (must be multiple of 8)
152 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, mSlaveBase
);
155 // ICW3: slave indentification code must be 2
157 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, 0x02);
160 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
162 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, 0x01);
165 // Restore interrupt mask register
167 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, Mask
);
171 // Set vector base for master PIC
173 if (MasterBase
!= mMasterBase
) {
174 mMasterBase
= MasterBase
;
177 // Initialization sequence is needed for setting vector base.
181 // Preserve interrtup mask register before initialization sequence
182 // because it will be cleared during intialization
184 Mask
= IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER
);
187 // ICW1: cascade mode, ICW4 write required
189 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER
, 0x11);
192 // ICW2: new vector base (must be multiple of 8)
194 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, mMasterBase
);
197 // ICW3: slave PIC is cascaded on IRQ2
199 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, 0x04);
202 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
204 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, 0x01);
207 // Restore interrupt mask register
209 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, Mask
);
212 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE
, LEGACY_8259_EOI
);
213 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER
, LEGACY_8259_EOI
);
219 Gets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
221 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
222 @param[out] LegacyMask 16-bit mode interrupt mask for IRQ0-IRQ15.
223 @param[out] LegacyEdgeLevel 16-bit mode edge/level mask for IRQ-IRQ15.
224 @param[out] ProtectedMask 32-bit mode interrupt mask for IRQ0-IRQ15.
225 @param[out] ProtectedEdgeLevel 32-bit mode edge/level mask for IRQ0-IRQ15.
227 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
228 @retval EFI_DEVICE_ERROR There was an error while reading the 8259 PIC.
233 Interrupt8259GetMask (
234 IN EFI_LEGACY_8259_PROTOCOL
*This
,
235 OUT UINT16
*LegacyMask
, OPTIONAL
236 OUT UINT16
*LegacyEdgeLevel
, OPTIONAL
237 OUT UINT16
*ProtectedMask
, OPTIONAL
238 OUT UINT16
*ProtectedEdgeLevel OPTIONAL
241 if (LegacyMask
!= NULL
) {
242 *LegacyMask
= mLegacyModeMask
;
245 if (LegacyEdgeLevel
!= NULL
) {
246 *LegacyEdgeLevel
= mLegacyModeEdgeLevel
;
249 if (ProtectedMask
!= NULL
) {
250 *ProtectedMask
= mProtectedModeMask
;
253 if (ProtectedEdgeLevel
!= NULL
) {
254 *ProtectedEdgeLevel
= mProtectedModeEdgeLevel
;
261 Sets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
263 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
264 @param[in] LegacyMask 16-bit mode interrupt mask for IRQ0-IRQ15.
265 @param[in] LegacyEdgeLevel 16-bit mode edge/level mask for IRQ-IRQ15.
266 @param[in] ProtectedMask 32-bit mode interrupt mask for IRQ0-IRQ15.
267 @param[in] ProtectedEdgeLevel 32-bit mode edge/level mask for IRQ0-IRQ15.
269 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
270 @retval EFI_DEVICE_ERROR There was an error while writing the 8259 PIC.
275 Interrupt8259SetMask (
276 IN EFI_LEGACY_8259_PROTOCOL
*This
,
277 IN UINT16
*LegacyMask
, OPTIONAL
278 IN UINT16
*LegacyEdgeLevel
, OPTIONAL
279 IN UINT16
*ProtectedMask
, OPTIONAL
280 IN UINT16
*ProtectedEdgeLevel OPTIONAL
283 if (LegacyMask
!= NULL
) {
284 mLegacyModeMask
= *LegacyMask
;
287 if (LegacyEdgeLevel
!= NULL
) {
288 mLegacyModeEdgeLevel
= *LegacyEdgeLevel
;
291 if (ProtectedMask
!= NULL
) {
292 mProtectedModeMask
= *ProtectedMask
;
295 if (ProtectedEdgeLevel
!= NULL
) {
296 mProtectedModeEdgeLevel
= *ProtectedEdgeLevel
;
303 Sets the mode of the PICs.
305 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
306 @param[in] Mode 16-bit real or 32-bit protected mode.
307 @param[in] Mask The value with which to set the interrupt mask.
308 @param[in] EdgeLevel The value with which to set the edge/level mask.
310 @retval EFI_SUCCESS The mode was set successfully.
311 @retval EFI_INVALID_PARAMETER The mode was not set.
316 Interrupt8259SetMode (
317 IN EFI_LEGACY_8259_PROTOCOL
*This
,
318 IN EFI_8259_MODE Mode
,
319 IN UINT16
*Mask
, OPTIONAL
320 IN UINT16
*EdgeLevel OPTIONAL
327 if (Mode
== Efi8259LegacyMode
) {
329 // In Efi8259ProtectedMode, mask and edge/level trigger registers should
330 // be changed through this protocol, so we can track them in the
331 // corresponding module variables.
333 Interrupt8259ReadMask (&mProtectedModeMask
, &mProtectedModeEdgeLevel
);
337 // Update the Mask for the new mode
339 mLegacyModeMask
= *Mask
;
342 if (EdgeLevel
!= NULL
) {
344 // Update the Edge/Level triggered mask for the new mode
346 mLegacyModeEdgeLevel
= *EdgeLevel
;
352 // Write new legacy mode mask/trigger level
354 Interrupt8259WriteMask (mLegacyModeMask
, mLegacyModeEdgeLevel
);
359 if (Mode
== Efi8259ProtectedMode
) {
361 // Save the legacy mode mask/trigger level
363 Interrupt8259ReadMask (&mLegacyModeMask
, &mLegacyModeEdgeLevel
);
365 // Always force Timer to be enabled after return from 16-bit code.
366 // This always insures that on next entry, timer is counting.
368 mLegacyModeMask
&= 0xFFFE;
372 // Update the Mask for the new mode
374 mProtectedModeMask
= *Mask
;
377 if (EdgeLevel
!= NULL
) {
379 // Update the Edge/Level triggered mask for the new mode
381 mProtectedModeEdgeLevel
= *EdgeLevel
;
387 // Write new protected mode mask/trigger level
389 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
394 return EFI_INVALID_PARAMETER
;
398 Translates the IRQ into a vector.
400 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
401 @param[in] Irq IRQ0-IRQ15.
402 @param[out] Vector The vector that is assigned to the IRQ.
404 @retval EFI_SUCCESS The Vector that matches Irq was returned.
405 @retval EFI_INVALID_PARAMETER Irq is not valid.
410 Interrupt8259GetVector (
411 IN EFI_LEGACY_8259_PROTOCOL
*This
,
416 if (Irq
< Efi8259Irq0
|| Irq
> Efi8259Irq15
) {
417 return EFI_INVALID_PARAMETER
;
420 if (Irq
<= Efi8259Irq7
) {
421 *Vector
= (UINT8
) (mMasterBase
+ Irq
);
423 *Vector
= (UINT8
) (mSlaveBase
+ (Irq
- Efi8259Irq8
));
430 Enables the specified IRQ.
432 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
433 @param[in] Irq IRQ0-IRQ15.
434 @param[in] LevelTriggered 0 = Edge triggered; 1 = Level triggered.
436 @retval EFI_SUCCESS The Irq was enabled on the 8259 PIC.
437 @retval EFI_INVALID_PARAMETER The Irq is not valid.
442 Interrupt8259EnableIrq (
443 IN EFI_LEGACY_8259_PROTOCOL
*This
,
445 IN BOOLEAN LevelTriggered
448 if (Irq
< Efi8259Irq0
|| Irq
> Efi8259Irq15
) {
449 return EFI_INVALID_PARAMETER
;
452 mProtectedModeMask
= (UINT16
) (mProtectedModeMask
& ~(1 << Irq
));
453 if (LevelTriggered
) {
454 mProtectedModeEdgeLevel
= (UINT16
) (mProtectedModeEdgeLevel
| (1 << Irq
));
456 mProtectedModeEdgeLevel
= (UINT16
) (mProtectedModeEdgeLevel
& ~(1 << Irq
));
459 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
465 Disables the specified IRQ.
467 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
468 @param[in] Irq IRQ0-IRQ15.
470 @retval EFI_SUCCESS The Irq was disabled on the 8259 PIC.
471 @retval EFI_INVALID_PARAMETER The Irq is not valid.
476 Interrupt8259DisableIrq (
477 IN EFI_LEGACY_8259_PROTOCOL
*This
,
481 if (Irq
< Efi8259Irq0
|| Irq
> Efi8259Irq15
) {
482 return EFI_INVALID_PARAMETER
;
485 mProtectedModeMask
= (UINT16
) (mProtectedModeMask
| (1 << Irq
));
487 mProtectedModeEdgeLevel
= (UINT16
) (mProtectedModeEdgeLevel
& ~(1 << Irq
));
489 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
495 Reads the PCI configuration space to get the interrupt number that is assigned to the card.
497 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
498 @param[in] PciHandle PCI function for which to return the vector.
499 @param[out] Vector IRQ number that corresponds to the interrupt line.
501 @retval EFI_SUCCESS The interrupt line value was read successfully.
506 Interrupt8259GetInterruptLine (
507 IN EFI_LEGACY_8259_PROTOCOL
*This
,
508 IN EFI_HANDLE PciHandle
,
512 EFI_PCI_IO_PROTOCOL
*PciIo
;
516 Status
= gBS
->HandleProtocol (
518 &gEfiPciIoProtocolGuid
,
521 if (EFI_ERROR (Status
)) {
522 return EFI_INVALID_PARAMETER
;
533 // Interrupt line is same location for standard PCI cards, standard
534 // bridge and CardBus bridge.
536 *Vector
= InterruptLine
;
542 Issues the End of Interrupt (EOI) commands to PICs.
544 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
545 @param[in] Irq The interrupt for which to issue the EOI command.
547 @retval EFI_SUCCESS The EOI command was issued.
548 @retval EFI_INVALID_PARAMETER The Irq is not valid.
553 Interrupt8259EndOfInterrupt (
554 IN EFI_LEGACY_8259_PROTOCOL
*This
,
558 if (Irq
< Efi8259Irq0
|| Irq
> Efi8259Irq15
) {
559 return EFI_INVALID_PARAMETER
;
562 if (Irq
>= Efi8259Irq8
) {
563 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE
, LEGACY_8259_EOI
);
566 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER
, LEGACY_8259_EOI
);
574 @param[in] ImageHandle ImageHandle of the loaded driver.
575 @param[in] SystemTable Pointer to the EFI System Table.
577 @retval EFI_SUCCESS One or more of the drivers returned a success code.
578 @retval !EFI_SUCCESS Error installing Legacy 8259 Protocol.
584 IN EFI_HANDLE ImageHandle
,
585 IN EFI_SYSTEM_TABLE
*SystemTable
592 // Clear all pending interrupt
594 for (Irq
= Efi8259Irq0
; Irq
<= Efi8259Irq15
; Irq
++) {
595 Interrupt8259EndOfInterrupt (&mInterrupt8259
, Irq
);
599 // Set the 8259 Master base to 0x68 and the 8259 Slave base to 0x70
601 Status
= Interrupt8259SetVectorBase (&mInterrupt8259
, PROTECTED_MODE_BASE_VECTOR_MASTER
, PROTECTED_MODE_BASE_VECTOR_SLAVE
);
604 // Set all 8259 interrupts to edge triggered and disabled
606 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
609 // Install 8259 Protocol onto a new handle
611 Status
= gBS
->InstallProtocolInterface (
613 &gEfiLegacy8259ProtocolGuid
,
614 EFI_NATIVE_INTERFACE
,