2 This contains the installation function for the driver.
4 Copyright (c) 2005 - 2018, 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
;
42 UINT16 mProtectedModeEdgeLevel
= 0x0000;
43 UINT16 mLegacyModeEdgeLevel
;
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 OriginalTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
131 // Set vector base for slave PIC
133 if (SlaveBase
!= mSlaveBase
) {
134 mSlaveBase
= SlaveBase
;
137 // Initialization sequence is needed for setting vector base.
141 // Preserve interrtup mask register before initialization sequence
142 // because it will be cleared during initialization
144 Mask
= IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE
);
147 // ICW1: cascade mode, ICW4 write required
149 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE
, 0x11);
152 // ICW2: new vector base (must be multiple of 8)
154 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, mSlaveBase
);
157 // ICW3: slave indentification code must be 2
159 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, 0x02);
162 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
164 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, 0x01);
167 // Restore interrupt mask register
169 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, Mask
);
173 // Set vector base for master PIC
175 if (MasterBase
!= mMasterBase
) {
176 mMasterBase
= MasterBase
;
179 // Initialization sequence is needed for setting vector base.
183 // Preserve interrtup mask register before initialization sequence
184 // because it will be cleared during initialization
186 Mask
= IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER
);
189 // ICW1: cascade mode, ICW4 write required
191 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER
, 0x11);
194 // ICW2: new vector base (must be multiple of 8)
196 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, mMasterBase
);
199 // ICW3: slave PIC is cascaded on IRQ2
201 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, 0x04);
204 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
206 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, 0x01);
209 // Restore interrupt mask register
211 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, Mask
);
214 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE
, LEGACY_8259_EOI
);
215 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER
, LEGACY_8259_EOI
);
217 gBS
->RestoreTPL (OriginalTpl
);
223 Gets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
225 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
226 @param[out] LegacyMask 16-bit mode interrupt mask for IRQ0-IRQ15.
227 @param[out] LegacyEdgeLevel 16-bit mode edge/level mask for IRQ-IRQ15.
228 @param[out] ProtectedMask 32-bit mode interrupt mask for IRQ0-IRQ15.
229 @param[out] ProtectedEdgeLevel 32-bit mode edge/level mask for IRQ0-IRQ15.
231 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
232 @retval EFI_DEVICE_ERROR There was an error while reading the 8259 PIC.
237 Interrupt8259GetMask (
238 IN EFI_LEGACY_8259_PROTOCOL
*This
,
239 OUT UINT16
*LegacyMask
, OPTIONAL
240 OUT UINT16
*LegacyEdgeLevel
, OPTIONAL
241 OUT UINT16
*ProtectedMask
, OPTIONAL
242 OUT UINT16
*ProtectedEdgeLevel OPTIONAL
245 if (LegacyMask
!= NULL
) {
246 *LegacyMask
= mLegacyModeMask
;
249 if (LegacyEdgeLevel
!= NULL
) {
250 *LegacyEdgeLevel
= mLegacyModeEdgeLevel
;
253 if (ProtectedMask
!= NULL
) {
254 *ProtectedMask
= mProtectedModeMask
;
257 if (ProtectedEdgeLevel
!= NULL
) {
258 *ProtectedEdgeLevel
= mProtectedModeEdgeLevel
;
265 Sets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
267 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
268 @param[in] LegacyMask 16-bit mode interrupt mask for IRQ0-IRQ15.
269 @param[in] LegacyEdgeLevel 16-bit mode edge/level mask for IRQ-IRQ15.
270 @param[in] ProtectedMask 32-bit mode interrupt mask for IRQ0-IRQ15.
271 @param[in] ProtectedEdgeLevel 32-bit mode edge/level mask for IRQ0-IRQ15.
273 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
274 @retval EFI_DEVICE_ERROR There was an error while writing the 8259 PIC.
279 Interrupt8259SetMask (
280 IN EFI_LEGACY_8259_PROTOCOL
*This
,
281 IN UINT16
*LegacyMask
, OPTIONAL
282 IN UINT16
*LegacyEdgeLevel
, OPTIONAL
283 IN UINT16
*ProtectedMask
, OPTIONAL
284 IN UINT16
*ProtectedEdgeLevel OPTIONAL
287 if (LegacyMask
!= NULL
) {
288 mLegacyModeMask
= *LegacyMask
;
291 if (LegacyEdgeLevel
!= NULL
) {
292 mLegacyModeEdgeLevel
= *LegacyEdgeLevel
;
295 if (ProtectedMask
!= NULL
) {
296 mProtectedModeMask
= *ProtectedMask
;
299 if (ProtectedEdgeLevel
!= NULL
) {
300 mProtectedModeEdgeLevel
= *ProtectedEdgeLevel
;
307 Sets the mode of the PICs.
309 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
310 @param[in] Mode 16-bit real or 32-bit protected mode.
311 @param[in] Mask The value with which to set the interrupt mask.
312 @param[in] EdgeLevel The value with which to set the edge/level mask.
314 @retval EFI_SUCCESS The mode was set successfully.
315 @retval EFI_INVALID_PARAMETER The mode was not set.
320 Interrupt8259SetMode (
321 IN EFI_LEGACY_8259_PROTOCOL
*This
,
322 IN EFI_8259_MODE Mode
,
323 IN UINT16
*Mask
, OPTIONAL
324 IN UINT16
*EdgeLevel OPTIONAL
331 if (Mode
== Efi8259LegacyMode
) {
333 // In Efi8259ProtectedMode, mask and edge/level trigger registers should
334 // be changed through this protocol, so we can track them in the
335 // corresponding module variables.
337 Interrupt8259ReadMask (&mProtectedModeMask
, &mProtectedModeEdgeLevel
);
341 // Update the Mask for the new mode
343 mLegacyModeMask
= *Mask
;
346 if (EdgeLevel
!= NULL
) {
348 // Update the Edge/Level triggered mask for the new mode
350 mLegacyModeEdgeLevel
= *EdgeLevel
;
356 // Write new legacy mode mask/trigger level
358 Interrupt8259WriteMask (mLegacyModeMask
, mLegacyModeEdgeLevel
);
363 if (Mode
== Efi8259ProtectedMode
) {
365 // Save the legacy mode mask/trigger level
367 Interrupt8259ReadMask (&mLegacyModeMask
, &mLegacyModeEdgeLevel
);
369 // Always force Timer to be enabled after return from 16-bit code.
370 // This always insures that on next entry, timer is counting.
372 mLegacyModeMask
&= 0xFFFE;
376 // Update the Mask for the new mode
378 mProtectedModeMask
= *Mask
;
381 if (EdgeLevel
!= NULL
) {
383 // Update the Edge/Level triggered mask for the new mode
385 mProtectedModeEdgeLevel
= *EdgeLevel
;
391 // Write new protected mode mask/trigger level
393 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
398 return EFI_INVALID_PARAMETER
;
402 Translates the IRQ into a vector.
404 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
405 @param[in] Irq IRQ0-IRQ15.
406 @param[out] Vector The vector that is assigned to the IRQ.
408 @retval EFI_SUCCESS The Vector that matches Irq was returned.
409 @retval EFI_INVALID_PARAMETER Irq is not valid.
414 Interrupt8259GetVector (
415 IN EFI_LEGACY_8259_PROTOCOL
*This
,
420 if ((UINT32
)Irq
> Efi8259Irq15
) {
421 return EFI_INVALID_PARAMETER
;
424 if (Irq
<= Efi8259Irq7
) {
425 *Vector
= (UINT8
) (mMasterBase
+ Irq
);
427 *Vector
= (UINT8
) (mSlaveBase
+ (Irq
- Efi8259Irq8
));
434 Enables the specified IRQ.
436 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
437 @param[in] Irq IRQ0-IRQ15.
438 @param[in] LevelTriggered 0 = Edge triggered; 1 = Level triggered.
440 @retval EFI_SUCCESS The Irq was enabled on the 8259 PIC.
441 @retval EFI_INVALID_PARAMETER The Irq is not valid.
446 Interrupt8259EnableIrq (
447 IN EFI_LEGACY_8259_PROTOCOL
*This
,
449 IN BOOLEAN LevelTriggered
452 if ((UINT32
)Irq
> Efi8259Irq15
) {
453 return EFI_INVALID_PARAMETER
;
456 mProtectedModeMask
= (UINT16
) (mProtectedModeMask
& ~(1 << Irq
));
457 if (LevelTriggered
) {
458 mProtectedModeEdgeLevel
= (UINT16
) (mProtectedModeEdgeLevel
| (1 << Irq
));
460 mProtectedModeEdgeLevel
= (UINT16
) (mProtectedModeEdgeLevel
& ~(1 << Irq
));
463 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
469 Disables the specified IRQ.
471 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
472 @param[in] Irq IRQ0-IRQ15.
474 @retval EFI_SUCCESS The Irq was disabled on the 8259 PIC.
475 @retval EFI_INVALID_PARAMETER The Irq is not valid.
480 Interrupt8259DisableIrq (
481 IN EFI_LEGACY_8259_PROTOCOL
*This
,
485 if ((UINT32
)Irq
> Efi8259Irq15
) {
486 return EFI_INVALID_PARAMETER
;
489 mProtectedModeMask
= (UINT16
) (mProtectedModeMask
| (1 << Irq
));
491 mProtectedModeEdgeLevel
= (UINT16
) (mProtectedModeEdgeLevel
& ~(1 << Irq
));
493 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
499 Reads the PCI configuration space to get the interrupt number that is assigned to the card.
501 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
502 @param[in] PciHandle PCI function for which to return the vector.
503 @param[out] Vector IRQ number that corresponds to the interrupt line.
505 @retval EFI_SUCCESS The interrupt line value was read successfully.
510 Interrupt8259GetInterruptLine (
511 IN EFI_LEGACY_8259_PROTOCOL
*This
,
512 IN EFI_HANDLE PciHandle
,
516 EFI_PCI_IO_PROTOCOL
*PciIo
;
520 Status
= gBS
->HandleProtocol (
522 &gEfiPciIoProtocolGuid
,
525 if (EFI_ERROR (Status
)) {
526 return EFI_INVALID_PARAMETER
;
537 // Interrupt line is same location for standard PCI cards, standard
538 // bridge and CardBus bridge.
540 *Vector
= InterruptLine
;
546 Issues the End of Interrupt (EOI) commands to PICs.
548 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
549 @param[in] Irq The interrupt for which to issue the EOI command.
551 @retval EFI_SUCCESS The EOI command was issued.
552 @retval EFI_INVALID_PARAMETER The Irq is not valid.
557 Interrupt8259EndOfInterrupt (
558 IN EFI_LEGACY_8259_PROTOCOL
*This
,
562 if ((UINT32
)Irq
> Efi8259Irq15
) {
563 return EFI_INVALID_PARAMETER
;
566 if (Irq
>= Efi8259Irq8
) {
567 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE
, LEGACY_8259_EOI
);
570 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER
, LEGACY_8259_EOI
);
578 @param[in] ImageHandle ImageHandle of the loaded driver.
579 @param[in] SystemTable Pointer to the EFI System Table.
581 @retval EFI_SUCCESS One or more of the drivers returned a success code.
582 @retval !EFI_SUCCESS Error installing Legacy 8259 Protocol.
588 IN EFI_HANDLE ImageHandle
,
589 IN EFI_SYSTEM_TABLE
*SystemTable
596 // Initialze mask values from PCDs
598 mLegacyModeMask
= PcdGet16 (Pcd8259LegacyModeMask
);
599 mLegacyModeEdgeLevel
= PcdGet16 (Pcd8259LegacyModeEdgeLevel
);
602 // Clear all pending interrupt
604 for (Irq
= Efi8259Irq0
; Irq
<= Efi8259Irq15
; Irq
++) {
605 Interrupt8259EndOfInterrupt (&mInterrupt8259
, Irq
);
609 // Set the 8259 Master base to 0x68 and the 8259 Slave base to 0x70
611 Status
= Interrupt8259SetVectorBase (&mInterrupt8259
, PROTECTED_MODE_BASE_VECTOR_MASTER
, PROTECTED_MODE_BASE_VECTOR_SLAVE
);
614 // Set all 8259 interrupts to edge triggered and disabled
616 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
619 // Install 8259 Protocol onto a new handle
621 Status
= gBS
->InstallProtocolInterface (
623 &gEfiLegacy8259ProtocolGuid
,
624 EFI_NATIVE_INTERFACE
,