]> git.proxmox.com Git - mirror_edk2.git/blob - PcAtChipsetPkg/8259InterruptControllerDxe/8259.c
Move IntelFrameworkModulePkg/Universal/Legacy8259Dxe to
[mirror_edk2.git] / PcAtChipsetPkg / 8259InterruptControllerDxe / 8259.c
1 /**@file
2 This contains the installation function for the driver.
3
4 Copyright (c) 2005 - 2008, 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 prodiced 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 VOID
49 Interrupt8259WriteMask (
50 IN UINT16 Mask,
51 IN UINT16 EdgeLevel
52 )
53 /**
54
55 Routine Description:
56 Sets the 8250 mask to the valud specified by Mask
57
58 Arguments:
59 Mask - A 16 bit valute that represents the master and slave mask values
60
61 Returns:
62 None
63
64 **/
65 // TODO: EdgeLevel - add argument and description to function comment
66 {
67 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, (UINT8) Mask);
68 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, (UINT8) (Mask >> 8));
69 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER, (UINT8) EdgeLevel);
70 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE, (UINT8) (EdgeLevel >> 8));
71 }
72
73 VOID
74 Interrupt8259ReadMask (
75 IN UINT16 *Mask,
76 IN UINT16 *EdgeLevel
77 )
78 /**
79
80 Routine Description:
81 Sets the 8250 mask to the valud specified by Mask
82
83 Arguments:
84 Mask - A 16 bit valute that represents the master and slave mask values
85
86 Returns:
87 None
88
89 **/
90 // TODO: EdgeLevel - add argument and description to function comment
91 {
92 UINT16 MasterValue;
93 UINT16 SlaveValue;
94
95 if (Mask != NULL) {
96 MasterValue = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);
97 SlaveValue = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);
98
99 *Mask = (UINT16) (MasterValue | (SlaveValue << 8));
100 }
101
102 if (EdgeLevel != NULL) {
103 MasterValue = IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER);
104 SlaveValue = IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE);
105
106 *EdgeLevel = (UINT16) (MasterValue | (SlaveValue << 8));
107 }
108 }
109 //
110 // Legacy 8259 Protocol Interface Function
111 //
112 EFI_STATUS
113 EFIAPI
114 Interrupt8259SetVectorBase (
115 IN EFI_LEGACY_8259_PROTOCOL *This,
116 IN UINT8 MasterBase,
117 IN UINT8 SlaveBase
118 )
119 /**
120
121 Routine Description:
122 Sets the base vector for the 8250 Master and Slave interrupt controllers
123
124 Arguments:
125 This - Protocol instance pointer.
126 MasterBase - Base vector of the 8259 Master
127 SlaveBase - Base vector of the 8259 Slave
128
129 Returns:
130 EFI_SUCCESS - 8259 programmed
131
132 **/
133 {
134 UINT8 Mask;
135
136 if (SlaveBase != mSlaveBase) {
137 mSlaveBase = SlaveBase;
138
139 //
140 // Initialize Slave interrupt controller.
141 //
142 Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);
143 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, 0x11);
144 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, mSlaveBase);
145 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x02);
146 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x01);
147 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, Mask);
148 }
149
150 if (MasterBase != mMasterBase) {
151 mMasterBase = MasterBase;
152
153 //
154 // Initialize Master interrupt controller.
155 //
156 Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);
157 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, 0x11);
158 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, mMasterBase);
159 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x04);
160 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x01);
161 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, Mask);
162 }
163
164 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, 0x20);
165 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, 0x20);
166
167 return EFI_SUCCESS;
168 }
169
170 EFI_STATUS
171 EFIAPI
172 Interrupt8259GetMask (
173 IN EFI_LEGACY_8259_PROTOCOL * This,
174 OUT UINT16 *LegacyMask, OPTIONAL
175 OUT UINT16 *LegacyEdgeLevel, OPTIONAL
176 OUT UINT16 *ProtectedMask, OPTIONAL
177 OUT UINT16 *ProtectedEdgeLevel OPTIONAL
178 )
179 /**
180
181 Routine Description:
182 Get the 8259 master and slave address that maps IRQ to processor interrupt
183 vector number. Get the Context of the device including the state of the
184 interrupt mask.
185
186 Arguments:
187 This - Protocol instance pointer.
188
189 Returns:
190 EFI_SUCCESS - 8259 programmed
191 EFI_DEVICE_ERROR - Error writting to 8259
192
193 **/
194 // TODO: LegacyMask - add argument and description to function comment
195 // TODO: LegacyEdgeLevel - add argument and description to function comment
196 // TODO: ProtectedMask - add argument and description to function comment
197 // TODO: ProtectedEdgeLevel - add argument and description to function comment
198 {
199 if (LegacyMask != NULL) {
200 *LegacyMask = mLegacyModeMask;
201 }
202
203 if (LegacyEdgeLevel != NULL) {
204 *LegacyEdgeLevel = mLegacyModeEdgeLevel;
205 }
206
207 if (ProtectedMask != NULL) {
208 *ProtectedMask = mProtectedModeMask;
209 }
210
211 if (ProtectedEdgeLevel != NULL) {
212 *ProtectedEdgeLevel = mProtectedModeEdgeLevel;
213 }
214
215 return EFI_SUCCESS;
216 }
217
218 EFI_STATUS
219 EFIAPI
220 Interrupt8259SetMask (
221 IN EFI_LEGACY_8259_PROTOCOL * This,
222 IN UINT16 *LegacyMask, OPTIONAL
223 IN UINT16 *LegacyEdgeLevel, OPTIONAL
224 IN UINT16 *ProtectedMask, OPTIONAL
225 IN UINT16 *ProtectedEdgeLevel OPTIONAL
226 )
227 /**
228
229 Routine Description:
230 Set the 8259 interrupt and edge/level masks for legacy and/or protected
231 mode operation. This routine does not touch the hardware but only the
232 RAM copies of the masks.
233
234 Arguments:
235 This - Protocol instance pointer.
236
237 Returns:
238 EFI_SUCCESS - 8259 masks updated
239
240 **/
241 // TODO: LegacyMask - add argument and description to function comment
242 // TODO: LegacyEdgeLevel - add argument and description to function comment
243 // TODO: ProtectedMask - add argument and description to function comment
244 // TODO: ProtectedEdgeLevel - add argument and description to function comment
245 {
246 if (LegacyMask != NULL) {
247 mLegacyModeMask = *LegacyMask;
248 }
249
250 if (LegacyEdgeLevel != NULL) {
251 mLegacyModeEdgeLevel = *LegacyEdgeLevel;
252 }
253
254 if (ProtectedMask != NULL) {
255 mProtectedModeMask = *ProtectedMask;
256 }
257
258 if (ProtectedEdgeLevel != NULL) {
259 mProtectedModeEdgeLevel = *ProtectedEdgeLevel;
260 }
261
262 return EFI_SUCCESS;
263 }
264
265 EFI_STATUS
266 EFIAPI
267 Interrupt8259SetMode (
268 IN EFI_LEGACY_8259_PROTOCOL * This,
269 IN EFI_8259_MODE Mode,
270 IN UINT16 *Mask, OPTIONAL
271 IN UINT16 *EdgeLevel OPTIONAL
272 )
273 /**
274
275 Routine Description:
276 Set the 8259 master and slave address that maps IRQ to processor interrupt
277 vector number. Restore the Context of the device, so that the interrupt
278 mask is put back in it's previous mode.
279
280 Arguments:
281 This - Protocol instance pointer.
282 Mode -
283 Mask -
284
285 Returns:
286 EFI_SUCCESS - 8259 programmed
287 EFI_DEVICE_ERROR - Error writting to 8259
288
289 **/
290 // TODO: EdgeLevel - add argument and description to function comment
291 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
292 {
293 if (Mode == mMode) {
294 return EFI_SUCCESS;
295 }
296
297 if (Mode == Efi8259LegacyMode) {
298 //
299 // Save the protected mode mask
300 //
301 Interrupt8259ReadMask (&mProtectedModeMask, &mProtectedModeEdgeLevel);
302
303 if (Mask != NULL) {
304 //
305 // Update the Mask for the new mode
306 //
307 mLegacyModeMask = *Mask;
308 }
309
310 if (EdgeLevel != NULL) {
311 //
312 // Update the Edge/Level triggered mask for the new mode
313 //
314 mLegacyModeEdgeLevel = *EdgeLevel;
315 }
316
317 mMode = Mode;
318
319 //
320 // Set 8259 Vector Base
321 //
322 //
323 Interrupt8259SetVectorBase (This, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
324
325 //
326 // Enable Interrupts
327 //
328 Interrupt8259WriteMask (mLegacyModeMask, mLegacyModeEdgeLevel);
329
330 return EFI_SUCCESS;
331 }
332
333 if (Mode == Efi8259ProtectedMode) {
334 //
335 // Save the legacy mode mask
336 //
337 Interrupt8259ReadMask (&mLegacyModeMask, &mLegacyModeEdgeLevel);
338 //
339 // Always force Timer to be enabled after return from 16-bit code.
340 // This always insures that on next entry, timer is counting.
341 //
342 mLegacyModeMask &= 0xFFFE;
343
344 if (Mask != NULL) {
345 //
346 // Update the Mask for the new mode
347 //
348 mProtectedModeMask = *Mask;
349 }
350
351 if (EdgeLevel != NULL) {
352 //
353 // Update the Edge/Level triggered mask for the new mode
354 //
355 mProtectedModeEdgeLevel = *EdgeLevel;
356 }
357
358 mMode = Mode;
359
360 //
361 // Set 8259 Vector Base
362 //
363 //
364 Interrupt8259SetVectorBase (This, PROTECTED_MODE_BASE_VECTOR_MASTER, PROTECTED_MODE_BASE_VECTOR_SLAVE);
365
366 //
367 // Enable Interrupts
368 //
369 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
370
371 return EFI_SUCCESS;
372 }
373
374 return EFI_INVALID_PARAMETER;
375 }
376
377 EFI_STATUS
378 EFIAPI
379 Interrupt8259GetVector (
380 IN EFI_LEGACY_8259_PROTOCOL *This,
381 IN EFI_8259_IRQ Irq,
382 OUT UINT8 *Vector
383 )
384 /**
385
386 Routine Description:
387 Convert from IRQ to processor interrupt vector number.
388
389 Arguments:
390 This - Protocol instance pointer.
391 Irq - 8259 IRQ0 - IRQ15
392 Vector - Processor vector number that matches Irq
393
394 Returns:
395 EFI_SUCCESS - The Vector matching Irq is returned
396 EFI_INVALID_PARAMETER - Irq not valid
397
398 **/
399 {
400 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
401 return EFI_INVALID_PARAMETER;
402 }
403
404 if (Irq <= Efi8259Irq7) {
405 *Vector = (UINT8) (mMasterBase + Irq);
406 } else {
407 *Vector = (UINT8) (mSlaveBase + (Irq - Efi8259Irq8));
408 }
409
410 return EFI_SUCCESS;
411 }
412
413 EFI_STATUS
414 EFIAPI
415 Interrupt8259EnableIrq (
416 IN EFI_LEGACY_8259_PROTOCOL *This,
417 IN EFI_8259_IRQ Irq,
418 IN BOOLEAN LevelTriggered
419 )
420 /**
421
422 Routine Description:
423 Enable Irq by unmasking interrupt in 8259
424
425 Arguments:
426 This - Protocol instance pointer.
427 Irq - 8259 IRQ0 - IRQ15
428
429 Returns:
430 EFI_SUCCESS - Irq enabled on 8259
431 EFI_INVALID_PARAMETER - Irq not valid
432
433 **/
434 // TODO: LevelTriggered - add argument and description to function comment
435 {
436 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
437 return EFI_INVALID_PARAMETER;
438 }
439
440 mProtectedModeMask = (UINT16) (mProtectedModeMask & ~(1 << Irq));
441 if (LevelTriggered) {
442 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel | (1 << Irq));
443 } else {
444 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel & ~(1 << Irq));
445 }
446
447 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
448
449 return EFI_SUCCESS;
450 }
451
452 EFI_STATUS
453 EFIAPI
454 Interrupt8259DisableIrq (
455 IN EFI_LEGACY_8259_PROTOCOL *This,
456 IN EFI_8259_IRQ Irq
457 )
458 /**
459
460 Routine Description:
461 Disable Irq by masking interrupt in 8259
462
463 Arguments:
464 This - Protocol instance pointer.
465 Irq - 8259 IRQ0 - IRQ15
466
467 Returns:
468 EFI_SUCCESS - Irq disabled on 8259
469 EFI_INVALID_PARAMETER - Irq not valid
470
471 **/
472 {
473 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
474 return EFI_INVALID_PARAMETER;
475 }
476
477 mProtectedModeMask = (UINT16) (mProtectedModeMask | (1 << Irq));
478 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel & ~(1 << Irq));
479
480 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
481
482 return EFI_SUCCESS;
483 }
484
485 EFI_STATUS
486 EFIAPI
487 Interrupt8259GetInterruptLine (
488 IN EFI_LEGACY_8259_PROTOCOL *This,
489 IN EFI_HANDLE PciHandle,
490 OUT UINT8 *Vector
491 )
492 /**
493
494 Routine Description:
495 PciHandle represents a PCI config space of a PCI function. Vector
496 represents Interrupt Pin (from PCI config space) and it is the data
497 that is programmed into the Interrupt Line (from the PCI config space)
498 register.
499
500 Arguments:
501 This - Protocol instance pointer.
502 PciHandle - PCI function to return vector for
503 Vector - Vector for fucntion that matches
504
505 Returns:
506 EFI_SUCCESS - A valid Vector is returned
507 EFI_INVALID_PARAMETER - PciHandle not valid
508
509 **/
510 {
511 return EFI_UNSUPPORTED;
512 }
513
514 EFI_STATUS
515 EFIAPI
516 Interrupt8259EndOfInterrupt (
517 IN EFI_LEGACY_8259_PROTOCOL *This,
518 IN EFI_8259_IRQ Irq
519 )
520 /**
521
522 Routine Description:
523 Send an EOI to 8259
524
525 Arguments:
526 This - Protocol instance pointer.
527 Irq - 8259 IRQ0 - IRQ15
528
529 Returns:
530 EFI_SUCCESS - EOI successfully sent to 8259
531 EFI_INVALID_PARAMETER - Irq not valid
532
533 **/
534 {
535 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {
536 return EFI_INVALID_PARAMETER;
537 }
538
539 if (Irq >= Efi8259Irq8) {
540 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, LEGACY_8259_EOI);
541 }
542
543 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, LEGACY_8259_EOI);
544
545 return EFI_SUCCESS;
546 }
547
548 //
549 // Legacy 8259 Driver Entry Point
550 //
551 EFI_STATUS
552 EFIAPI
553 Install8259 (
554 IN EFI_HANDLE ImageHandle,
555 IN EFI_SYSTEM_TABLE *SystemTable
556 )
557 /**
558
559 Routine Description:
560
561
562 Arguments:
563
564 (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
565
566 Returns:
567
568 EFI_SUCCESS - Legacy 8259 Protocol Installed
569
570 **/
571 // TODO: ImageHandle - add argument and description to function comment
572 // TODO: SystemTable - add argument and description to function comment
573 {
574 EFI_STATUS Status;
575 EFI_8259_IRQ Irq;
576
577 //
578 // Clear all pending interrupt
579 //
580 for (Irq = Efi8259Irq0; Irq <= Efi8259Irq15; Irq++) {
581 Interrupt8259EndOfInterrupt (&m8259, Irq);
582 }
583
584 //
585 // Set the 8259 Master base to 0x68 and the 8259 Slave base to 0x70
586 //
587 Status = Interrupt8259SetVectorBase (&m8259, PROTECTED_MODE_BASE_VECTOR_MASTER, PROTECTED_MODE_BASE_VECTOR_SLAVE);
588
589 //
590 // Set all 8259 interrupts to edge triggered and disabled
591 //
592 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
593
594 //
595 // Install 8259 Protocol onto a new handle
596 //
597 Status = gBS->InstallProtocolInterface (
598 &m8259Handle,
599 &gEfiLegacy8259ProtocolGuid,
600 EFI_NATIVE_INTERFACE,
601 &m8259
602 );
603 return Status;
604 }
605