]> git.proxmox.com Git - mirror_edk2.git/blob - PcAtChipsetPkg/8259InterruptControllerDxe/8259.c
Merge improved comments into this driver.
[mirror_edk2.git] / PcAtChipsetPkg / 8259InterruptControllerDxe / 8259.c
1 /**@file
2 This contains the installation function for the driver.
3
4 Copyright (c) 2005 - 2009, Intel Corporation
5 All rights reserved. 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
9
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.
12
13 **/
14
15 #include "8259.h"
16
17 //
18 // Global for the Legacy 8259 Protocol that is produced by this driver
19 //
20 EFI_LEGACY_8259_PROTOCOL m8259 = {
21 Interrupt8259SetVectorBase,
22 Interrupt8259GetMask,
23 Interrupt8259SetMask,
24 Interrupt8259SetMode,
25 Interrupt8259GetVector,
26 Interrupt8259EnableIrq,
27 Interrupt8259DisableIrq,
28 Interrupt8259GetInterruptLine,
29 Interrupt8259EndOfInterrupt
30 };
31
32 //
33 // Global for the handle that the Legacy 8259 Protocol is installed
34 //
35 EFI_HANDLE m8259Handle = NULL;
36
37 UINT8 mMasterBase = 0xff;
38 UINT8 mSlaveBase = 0xff;
39 EFI_8259_MODE mMode = Efi8259ProtectedMode;
40 UINT16 mProtectedModeMask = 0xffff;
41 UINT16 mLegacyModeMask = 0x06b8;
42 UINT16 mProtectedModeEdgeLevel = 0x0000;
43 UINT16 mLegacyModeEdgeLevel = 0x0000;
44
45 //
46 // Worker Functions
47 //
48
49 /**
50 Write to mask and edge/level triggered registers of master and slave PICs.
51
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.
56
57 **/
58 VOID
59 Interrupt8259WriteMask (
60 IN UINT16 Mask,
61 IN UINT16 EdgeLevel
62 )
63 {
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));
68 }
69
70 /**
71 Read from mask and edge/level triggered registers of master and slave PICs.
72
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.
77
78 **/
79 VOID
80 Interrupt8259ReadMask (
81 OUT UINT16 *Mask,
82 OUT UINT16 *EdgeLevel
83 )
84 {
85 UINT16 MasterValue;
86 UINT16 SlaveValue;
87
88 if (Mask != NULL) {
89 MasterValue = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);
90 SlaveValue = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);
91
92 *Mask = (UINT16) (MasterValue | (SlaveValue << 8));
93 }
94
95 if (EdgeLevel != NULL) {
96 MasterValue = IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER);
97 SlaveValue = IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE);
98
99 *EdgeLevel = (UINT16) (MasterValue | (SlaveValue << 8));
100 }
101 }
102
103 //
104 // Legacy 8259 Protocol Interface Functions
105 //
106
107 /**
108 Sets the base address for the 8259 master and slave PICs.
109
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.
113
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.
116
117 **/
118 EFI_STATUS
119 EFIAPI
120 Interrupt8259SetVectorBase (
121 IN EFI_LEGACY_8259_PROTOCOL *This,
122 IN UINT8 MasterBase,
123 IN UINT8 SlaveBase
124 )
125 {
126 UINT8 Mask;
127
128 //
129 // Set vector base for slave PIC
130 //
131 if (SlaveBase != mSlaveBase) {
132 mSlaveBase = SlaveBase;
133
134 //
135 // Initialization sequence is needed for setting vector base.
136 //
137
138 //
139 // Preserve interrtup mask register before initialization sequence
140 // because it will be cleared during intialization
141 //
142 Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);
143
144 //
145 // ICW1: cascade mode, ICW4 write required
146 //
147 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, 0x11);
148
149 //
150 // ICW2: new vector base (must be multiple of 8)
151 //
152 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, mSlaveBase);
153
154 //
155 // ICW3: slave indentification code must be 2
156 //
157 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x02);
158
159 //
160 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
161 //
162 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x01);
163
164 //
165 // Restore interrupt mask register
166 //
167 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, Mask);
168 }
169
170 //
171 // Set vector base for master PIC
172 //
173 if (MasterBase != mMasterBase) {
174 mMasterBase = MasterBase;
175
176 //
177 // Initialization sequence is needed for setting vector base.
178 //
179
180 //
181 // Preserve interrtup mask register before initialization sequence
182 // because it will be cleared during intialization
183 //
184 Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);
185
186 //
187 // ICW1: cascade mode, ICW4 write required
188 //
189 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, 0x11);
190
191 //
192 // ICW2: new vector base (must be multiple of 8)
193 //
194 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, mMasterBase);
195
196 //
197 // ICW3: slave PIC is cascaded on IRQ2
198 //
199 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x04);
200
201 //
202 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
203 //
204 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x01);
205
206 //
207 // Restore interrupt mask register
208 //
209 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, Mask);
210 }
211
212 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, 0x20);
213 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, 0x20);
214
215 return EFI_SUCCESS;
216 }
217
218 /**
219 Gets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
220
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.
226
227 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
228 @retval EFI_DEVICE_ERROR There was an error while reading the 8259 PIC.
229
230 **/
231 EFI_STATUS
232 EFIAPI
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
239 )
240 {
241 if (LegacyMask != NULL) {
242 *LegacyMask = mLegacyModeMask;
243 }
244
245 if (LegacyEdgeLevel != NULL) {
246 *LegacyEdgeLevel = mLegacyModeEdgeLevel;
247 }
248
249 if (ProtectedMask != NULL) {
250 *ProtectedMask = mProtectedModeMask;
251 }
252
253 if (ProtectedEdgeLevel != NULL) {
254 *ProtectedEdgeLevel = mProtectedModeEdgeLevel;
255 }
256
257 return EFI_SUCCESS;
258 }
259
260 /**
261 Sets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
262
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.
268
269 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
270 @retval EFI_DEVICE_ERROR There was an error while writing the 8259 PIC.
271
272 **/
273 EFI_STATUS
274 EFIAPI
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
281 )
282 {
283 if (LegacyMask != NULL) {
284 mLegacyModeMask = *LegacyMask;
285 }
286
287 if (LegacyEdgeLevel != NULL) {
288 mLegacyModeEdgeLevel = *LegacyEdgeLevel;
289 }
290
291 if (ProtectedMask != NULL) {
292 mProtectedModeMask = *ProtectedMask;
293 }
294
295 if (ProtectedEdgeLevel != NULL) {
296 mProtectedModeEdgeLevel = *ProtectedEdgeLevel;
297 }
298
299 return EFI_SUCCESS;
300 }
301
302 /**
303 Sets the mode of the PICs.
304
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.
309
310 @retval EFI_SUCCESS The mode was set successfully.
311 @retval EFI_INVALID_PARAMETER The mode was not set.
312
313 **/
314 EFI_STATUS
315 EFIAPI
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
321 )
322 {
323 if (Mode == mMode) {
324 return EFI_SUCCESS;
325 }
326
327 if (Mode == Efi8259LegacyMode) {
328 //
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.
332 //
333 Interrupt8259ReadMask (&mProtectedModeMask, &mProtectedModeEdgeLevel);
334
335 if (Mask != NULL) {
336 //
337 // Update the Mask for the new mode
338 //
339 mLegacyModeMask = *Mask;
340 }
341
342 if (EdgeLevel != NULL) {
343 //
344 // Update the Edge/Level triggered mask for the new mode
345 //
346 mLegacyModeEdgeLevel = *EdgeLevel;
347 }
348
349 mMode = Mode;
350
351 //
352 // Write new legacy mode mask/trigger level
353 //
354 Interrupt8259SetVectorBase (This, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
355
356 //
357 // Enable Interrupts
358 //
359 Interrupt8259WriteMask (mLegacyModeMask, mLegacyModeEdgeLevel);
360
361 return EFI_SUCCESS;
362 }
363
364 if (Mode == Efi8259ProtectedMode) {
365 //
366 // Save the legacy mode mask/trigger level
367 //
368 Interrupt8259ReadMask (&mLegacyModeMask, &mLegacyModeEdgeLevel);
369 //
370 // Always force Timer to be enabled after return from 16-bit code.
371 // This always insures that on next entry, timer is counting.
372 //
373 mLegacyModeMask &= 0xFFFE;
374
375 if (Mask != NULL) {
376 //
377 // Update the Mask for the new mode
378 //
379 mProtectedModeMask = *Mask;
380 }
381
382 if (EdgeLevel != NULL) {
383 //
384 // Update the Edge/Level triggered mask for the new mode
385 //
386 mProtectedModeEdgeLevel = *EdgeLevel;
387 }
388
389 mMode = Mode;
390
391 //
392 // Write new protected mode mask/trigger level
393 //
394 Interrupt8259SetVectorBase (This, PROTECTED_MODE_BASE_VECTOR_MASTER, PROTECTED_MODE_BASE_VECTOR_SLAVE);
395
396 //
397 // Enable Interrupts
398 //
399 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
400
401 return EFI_SUCCESS;
402 }
403
404 return EFI_INVALID_PARAMETER;
405 }
406
407 /**
408 Translates the IRQ into a vector.
409
410 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
411 @param[in] Irq IRQ0-IRQ15.
412 @param[out] Vector The vector that is assigned to the IRQ.
413
414 @retval EFI_SUCCESS The Vector that matches Irq was returned.
415 @retval EFI_INVALID_PARAMETER Irq is not valid.
416
417 **/
418 EFI_STATUS
419 EFIAPI
420 Interrupt8259GetVector (
421 IN EFI_LEGACY_8259_PROTOCOL *This,
422 IN EFI_8259_IRQ Irq,
423 OUT UINT8 *Vector
424 )
425 {
426 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
427 return EFI_INVALID_PARAMETER;
428 }
429
430 if (Irq <= Efi8259Irq7) {
431 *Vector = (UINT8) (mMasterBase + Irq);
432 } else {
433 *Vector = (UINT8) (mSlaveBase + (Irq - Efi8259Irq8));
434 }
435
436 return EFI_SUCCESS;
437 }
438
439 /**
440 Enables the specified IRQ.
441
442 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
443 @param[in] Irq IRQ0-IRQ15.
444 @param[in] LevelTriggered 0 = Edge triggered; 1 = Level triggered.
445
446 @retval EFI_SUCCESS The Irq was enabled on the 8259 PIC.
447 @retval EFI_INVALID_PARAMETER The Irq is not valid.
448
449 **/
450 EFI_STATUS
451 EFIAPI
452 Interrupt8259EnableIrq (
453 IN EFI_LEGACY_8259_PROTOCOL *This,
454 IN EFI_8259_IRQ Irq,
455 IN BOOLEAN LevelTriggered
456 )
457 {
458 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
459 return EFI_INVALID_PARAMETER;
460 }
461
462 mProtectedModeMask = (UINT16) (mProtectedModeMask & ~(1 << Irq));
463 if (LevelTriggered) {
464 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel | (1 << Irq));
465 } else {
466 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel & ~(1 << Irq));
467 }
468
469 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
470
471 return EFI_SUCCESS;
472 }
473
474 /**
475 Disables the specified IRQ.
476
477 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
478 @param[in] Irq IRQ0-IRQ15.
479
480 @retval EFI_SUCCESS The Irq was disabled on the 8259 PIC.
481 @retval EFI_INVALID_PARAMETER The Irq is not valid.
482
483 **/
484 EFI_STATUS
485 EFIAPI
486 Interrupt8259DisableIrq (
487 IN EFI_LEGACY_8259_PROTOCOL *This,
488 IN EFI_8259_IRQ Irq
489 )
490 {
491 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
492 return EFI_INVALID_PARAMETER;
493 }
494
495 mProtectedModeMask = (UINT16) (mProtectedModeMask | (1 << Irq));
496
497 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel & ~(1 << Irq));
498
499 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
500
501 return EFI_SUCCESS;
502 }
503
504 /**
505 Reads the PCI configuration space to get the interrupt number that is assigned to the card.
506
507 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
508 @param[in] PciHandle PCI function for which to return the vector.
509 @param[out] Vector IRQ number that corresponds to the interrupt line.
510
511 @retval EFI_SUCCESS The interrupt line value was read successfully.
512
513 **/
514 EFI_STATUS
515 EFIAPI
516 Interrupt8259GetInterruptLine (
517 IN EFI_LEGACY_8259_PROTOCOL *This,
518 IN EFI_HANDLE PciHandle,
519 OUT UINT8 *Vector
520 )
521 {
522 return EFI_UNSUPPORTED;
523 }
524
525 /**
526 Issues the End of Interrupt (EOI) commands to PICs.
527
528 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
529 @param[in] Irq The interrupt for which to issue the EOI command.
530
531 @retval EFI_SUCCESS The EOI command was issued.
532 @retval EFI_INVALID_PARAMETER The Irq is not valid.
533
534 **/
535 EFI_STATUS
536 EFIAPI
537 Interrupt8259EndOfInterrupt (
538 IN EFI_LEGACY_8259_PROTOCOL *This,
539 IN EFI_8259_IRQ Irq
540 )
541 {
542 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
543 return EFI_INVALID_PARAMETER;
544 }
545
546 if (Irq >= Efi8259Irq8) {
547 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, LEGACY_8259_EOI);
548 }
549
550 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, LEGACY_8259_EOI);
551
552 return EFI_SUCCESS;
553 }
554
555 /**
556 Driver Entry point.
557
558 @param[in] ImageHandle ImageHandle of the loaded driver.
559 @param[in] SystemTable Pointer to the EFI System Table.
560
561 @retval EFI_SUCCESS One or more of the drivers returned a success code.
562 @retval !EFI_SUCCESS Error installing Legacy 8259 Protocol.
563
564 **/
565 EFI_STATUS
566 EFIAPI
567 Install8259 (
568 IN EFI_HANDLE ImageHandle,
569 IN EFI_SYSTEM_TABLE *SystemTable
570 )
571 {
572 EFI_STATUS Status;
573 EFI_8259_IRQ Irq;
574
575 //
576 // Clear all pending interrupt
577 //
578 for (Irq = Efi8259Irq0; Irq <= Efi8259Irq15; Irq++) {
579 Interrupt8259EndOfInterrupt (&m8259, Irq);
580 }
581
582 //
583 // Set the 8259 Master base to 0x68 and the 8259 Slave base to 0x70
584 //
585 Status = Interrupt8259SetVectorBase (&m8259, PROTECTED_MODE_BASE_VECTOR_MASTER, PROTECTED_MODE_BASE_VECTOR_SLAVE);
586
587 //
588 // Set all 8259 interrupts to edge triggered and disabled
589 //
590 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
591
592 //
593 // Install 8259 Protocol onto a new handle
594 //
595 Status = gBS->InstallProtocolInterface (
596 &m8259Handle,
597 &gEfiLegacy8259ProtocolGuid,
598 EFI_NATIVE_INTERFACE,
599 &m8259
600 );
601 return Status;
602 }
603