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